import { EmailSelection } from '@/analyst/utilities'
import type { LinkType } from '@/components/LinkButton'
import LinkButton from '@/components/LinkButton'
import type { Path } from '@/router'
import { type IconName } from '@blueprintjs/core'
import type { Channel } from '@inject/graphql/fragment-types'
import { setIsUnreadChannel } from '@inject/graphql/mutations.client'
import { useEffect, useMemo, type FC } from 'react'
import { matchPath, useLocation } 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/:channelId/email/:tab`,
        {
          params: {
            exerciseId,
            teamId,
            channelId: channel.id,
            tab: 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}`)
  }
}

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}`)
  }

  const match = matchPath(
    {
      path,
      end: false,
    },
    pathname
  )

  return match !== null && match.params.channelId === channel.id
}

const ChannelButton: FC<ChannelButtonProps> = ({
  channel,
  exerciseId,
  teamId,
  linkTo,
  hideLabel,
}) => {
  const client = useClient()
  const { pathname } = useLocation()
  const active = useMemo(
    () => getActive(channel, linkTo, pathname),
    [channel, linkTo, pathname]
  )

  const isUnread = useMemo(() => {
    const needle = channel.readReceipt.find(
      readReceipt => readReceipt.teamId === teamId
    )
    return needle?.isUnread
  }, [channel.readReceipt, 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,
        intent: isUnread ? 'warning' : undefined,
        children,
        ellipsizeText: true,
      }}
    />
  )
}

export default ChannelButton
