import { EmailSelection } from '@/analyst/utilities'
import type { LinkType } from '@/components/LinkButton'
import LinkButton from '@/components/LinkButton'
import { canBeReviewed } from '@/instructor/InstructorQuestionnaire/utils'
import { type IconName } from '@blueprintjs/core'
import type {
  Channel,
  TeamQuestionnaireState,
} from '@inject/graphql/fragment-types'
import { useTypedQuery } from '@inject/graphql/graphql'
import { setIsUnreadChannel } from '@inject/graphql/mutations.client'
import { GetTeamChannelLogs } from '@inject/graphql/queries'
import { useEffect, useMemo, type FC } from 'react'
import { useMatch } from 'react-router-dom'
import { useClient } from 'urql'

export interface ChannelButtonProps {
  exerciseId: string
  teamId: string
  linkTo: 'trainee' | 'instructor'
  channel: Channel
  hideLabel?: boolean
}

export const getLink = (
  channel: Channel,
  exerciseId: string,
  teamId: string,
  linkTo: 'trainee' | 'instructor'
): LinkType => {
  switch (channel.type) {
    case 'INFO':
      return [
        `/${linkTo}/:exerciseId/:teamId/:channelId/info`,
        {
          params: {
            exerciseId,
            teamId,
            channelId: channel.id,
          },
        },
      ]
    case 'EMAIL':
      return [
        `/${linkTo}/:exerciseId/:teamId/email/:tab`,
        {
          params: {
            exerciseId,
            teamId,
            tab:
              linkTo === 'instructor'
                ? EmailSelection.SENT
                : EmailSelection.RECEIVED,
          },
        },
      ]
    case 'TOOL':
      return [
        `/${linkTo}/:exerciseId/:teamId/:channelId/tool`,
        {
          params: {
            exerciseId,
            teamId,
            channelId: channel.id,
          },
        },
      ]
    case 'FORM':
      return [
        `/${linkTo}/:exerciseId/:teamId/:channelId/form`,
        {
          params: {
            exerciseId,
            teamId,
            channelId: channel.id,
          },
        },
      ]
    default:
      throw new Error(`unknown channel type: ${channel.type}`)
  }
}

export const getIcon = (channelType: Channel['type']): IconName => {
  switch (channelType) {
    case 'INFO':
      return 'info-sign'
    case 'EMAIL':
      return 'envelope'
    case 'TOOL':
      return 'console'
    case 'FORM':
      return 'form'
    default:
      throw new Error(`unknown channel type: ${channelType}`)
  }
}

const getPath = (linkTo: 'trainee' | 'instructor', channel: Channel) => {
  switch (channel.type) {
    case 'EMAIL':
      return `/${linkTo}/:exerciseId/:teamId/email/`
    default:
      return `/${linkTo}/:exerciseId/:teamId/${channel.id}/`
  }
}

const ChannelButton: FC<ChannelButtonProps> = ({
  channel,
  exerciseId,
  teamId,
  linkTo,
  hideLabel,
}) => {
  const client = useClient()
  const [{ data }] = useTypedQuery({
    query: GetTeamChannelLogs,
    variables: {
      channelId: channel.id,
      teamId,
    },
    pause: channel.type !== 'FORM',
    context: useMemo(
      () => ({
        suspense: true,
      }),
      []
    ),
  })

  const active = useMatch({
    path: getPath(linkTo, channel),
    end: false,
  })

  const isUnread = useMemo(() => {
    if (channel.type !== 'FORM') {
      const needle = channel.readReceipt.find(
        readReceipt => readReceipt.teamId === teamId
      )
      return needle?.isUnread
    } else {
      const filteredLogs = data?.teamChannelLogs
        .filter(log => log.details.__typename === 'TeamQuestionnaireStateType')
        .map(log => log.details) as TeamQuestionnaireState[]
      if (linkTo === 'instructor') {
        return filteredLogs.some(
          form =>
            form.status === 'ANSWERED' &&
            canBeReviewed(form.answers.map(answer => answer.question))
        )
      } else {
        return filteredLogs.some(form => !form.timestampAnswered)
      }
    }
  }, [channel.readReceipt, channel.type, data?.teamChannelLogs, linkTo, teamId])

  useEffect(() => {
    // eslint-disable-next-line @typescript-eslint/no-unused-expressions
    isUnread &&
      active &&
      client
        .mutation(setIsUnreadChannel, {
          channelId: channel.id,
          teamId,
          isUnread: false,
        })
        .toPromise()
  }, [active, channel.id, client, isUnread, teamId])

  const children = useMemo(() => {
    if (hideLabel) {
      return undefined
    }
    if (isUnread) {
      return <b>{channel.displayName}</b>
    }
    return channel.displayName
  }, [channel.displayName, hideLabel, isUnread])

  return (
    <LinkButton
      key={channel.id}
      link={getLink(channel, exerciseId, teamId, linkTo)}
      button={{
        icon: getIcon(channel.type),
        title: channel.description || channel.displayName,
        fill: true,
        alignText: 'left',
        minimal: true,
        active: !!active,
        intent: isUnread ? 'warning' : undefined,
        children,
        ellipsizeText: true,
      }}
    />
  )
}

export default ChannelButton
