import { EmailSelection } from '@/analyst/utilities'
import type { LinkType } from '@/components/LinkButton'
import LinkButton from '@/components/LinkButton'
import type { Path } from '@/router'
import { Colors, type IconName } from '@blueprintjs/core'
import { Dot } from '@blueprintjs/icons'
import type { Channel } from '@inject/graphql/fragments/Channel.generated'
import { useSetIsUnreadChannel } from '@inject/graphql/mutations/clientonly/SetIsUnreadChannel.generated'
import type { ChannelType } from '@inject/graphql/types'
import { useMemo, type FC } from 'react'
import { matchPath } from 'react-router-dom'

export interface ChannelButtonProps {
  exerciseId: string
  teamId: string
  pathname: 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/:channelId/email/:tab`,
        {
          params: {
            exerciseId,
            teamId,
            channelId: channel.id,
            tab:
              linkTo === 'trainee'
                ? EmailSelection.RECEIVED
                : EmailSelection.SENT,
          },
        },
      ]
    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: ChannelType): 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}`)
  }
}

// TODO: check for channelId if multiple channels of the same type are allowed
export const getActive = (
  channel: Channel,
  linkTo: 'trainee' | 'instructor',
  pathname: string
): boolean => {
  let path: Path
  switch (channel.type) {
    case 'INFO':
      path = `/${linkTo}/:exerciseId/:teamId/:channelId/info`
      break
    case 'EMAIL':
      path = `/${linkTo}/:exerciseId/:teamId/:channelId/email`
      break
    case 'TOOL':
      path = `/${linkTo}/:exerciseId/:teamId/:channelId/tool`
      break
    case 'FORM':
      path = `/${linkTo}/:exerciseId/:teamId/:channelId/form`
      break
    default:
      throw new Error(`unknown channel type: ${channel.type}`)
  }

  return (
    matchPath(
      {
        path,
        end: false,
      },
      pathname
    ) !== null
  )
}

const ChannelButton: FC<ChannelButtonProps> = ({
  channel,
  exerciseId,
  teamId,
  pathname,
  linkTo,
  hideLabel,
}) => {
  const [setIsRead] = useSetIsUnreadChannel({
    variables: {
      channelId: channel.id,
      teamId,
      isUnread: false,
    },
  })

  const isUnread = useMemo(
    () =>
      channel.readReceipt.some(
        readReceipt => readReceipt.teamId === teamId && readReceipt.isUnread
      ),
    [channel.readReceipt, teamId]
  )

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

  return (
    <LinkButton
      key={getLink(channel, exerciseId, teamId, linkTo)[0].toString()}
      link={getLink(channel, exerciseId, teamId, linkTo)}
      button={{
        icon: getIcon(channel.type),
        title: channel.name,
        fill: true,
        alignText: 'left',
        minimal: true,
        active: getActive(channel, linkTo, pathname),
        intent: isUnread ? 'warning' : undefined,
        rightIcon: isUnread ? <Dot color={Colors.RED3} /> : undefined,
        onClick: setIsRead,
        children,
      }}
    />
  )
}

export default ChannelButton
