import type { IRootState } from '@/features/store';
import { createSelector } from '@reduxjs/toolkit';
import { createCachedSelector } from 're-reselect';

const DEFAULT_OBJECT = {};

export const channelsSelector = (state: IRootState) => state.server.channels;

export const selectedChannelIdSelector = (state: IRootState) =>
  state.server.selectedChannelId;

export const selectedChannelTypeSelector = createSelector(
  [channelsSelector, selectedChannelIdSelector],
  (channels, selectedChannelId) =>
    channels.find((channel) => channel.id === selectedChannelId)?.type
);

export const currentVoiceChannelIdSelector = (state: IRootState) =>
  state.server.currentVoiceChannelId;

export const currentVoiceServerIdSelector = (state: IRootState) =>
  state.server.currentVoiceServerId;

export const channelPermissionsSelector = (state: IRootState) =>
  state.server.channelPermissions;

export const channelsReadStatesSelector = (state: IRootState) =>
  state.server.readStatesMap;

export const channelReadStateByIdSelector = (
  state: IRootState,
  channelId: number
) => state.server.readStatesMap[channelId] ?? 0;

export const channelMentionCountByIdSelector = (
  state: IRootState,
  channelId: number
) => state.server.mentionStatesMap[channelId] ?? 0;

export const hasAnyUnreadSelector = (state: IRootState) =>
  Object.values(state.server.readStatesMap).some((count) => (count ?? 0) > 0);

export const lastReadMessageIdSelector = (
  state: IRootState,
  channelId: number
) => state.server.lastReadMessageIdMap[channelId];

export const channelByIdSelector = createCachedSelector(
  [channelsSelector, (_: IRootState, channelId: number) => channelId],
  (channels, channelId) => channels.find((channel) => channel.id === channelId)
)((_, channelId: number) => channelId);

export const channelsByCategoryIdSelector = createCachedSelector(
  [channelsSelector, (_: IRootState, categoryId: number) => categoryId],
  (channels, categoryId) =>
    channels
      .filter(
        (channel) =>
          channel.categoryId === categoryId && channel.type !== 'THREAD'
      )
      .sort((a, b) => a.position - b.position)
)((_, categoryId: number) => categoryId);

export const selectedChannelSelector = createSelector(
  [channelsSelector, selectedChannelIdSelector],
  (channels, selectedChannelId) =>
    channels.find((channel) => channel.id === selectedChannelId)
);

export const isCurrentVoiceChannelSelectedSelector = createSelector(
  [selectedChannelIdSelector, currentVoiceChannelIdSelector],
  (selectedChannelId, currentVoiceChannelId) =>
    currentVoiceChannelId !== undefined &&
    selectedChannelId === currentVoiceChannelId
);

export const channelPermissionsByIdSelector = (
  state: IRootState,
  channelId: number
) => state.server.channelPermissions[channelId] || DEFAULT_OBJECT;

export const activeThreadIdSelector = (state: IRootState) =>
  state.server.activeThreadId;

export const activeThreadSelector = createSelector(
  [channelsSelector, activeThreadIdSelector],
  (channels, activeThreadId) =>
    activeThreadId
      ? channels.find((channel) => channel.id === activeThreadId)
      : undefined
);

export const threadsByParentChannelIdSelector = createCachedSelector(
  [channelsSelector, (_: IRootState, parentChannelId: number) => parentChannelId],
  (channels, parentChannelId) =>
    channels.filter(
      (channel) =>
        channel.type === 'THREAD' && channel.parentChannelId === parentChannelId
    )
)((_: IRootState, parentChannelId: number) => `threads-${parentChannelId}`);
