import { Button, Classes, Icon } from '@blueprintjs/core'
import type { IconName } from '@blueprintjs/icons'
import { css } from '@emotion/css'
import type { ActionLog } from '@inject/graphql/fragments/ActionLog.generated'
import type { EmailDetails } from '@inject/graphql/fragments/EmailDetails.generated'
import type { InjectDetails } from '@inject/graphql/fragments/InjectDetails.generated'
import type { QuestionnaireDetails } from '@inject/graphql/fragments/QuestionnaireDetails.generated'
import type { ToolDetails } from '@inject/graphql/fragments/ToolDetails.generated'
import { useWriteReadReceipt } from '@inject/graphql/mutations/clientonly/WriteReadReceipt.generated'
import type { LogType } from '@inject/graphql/types'
import Message from '@inject/shared/components/Message'
import HeaderItem from '@inject/shared/components/Message/HeaderItem'
import Timestamp from '@inject/shared/components/Timestamp'
import { useEffect, useMemo, type FC, type MouseEventHandler } from 'react'
import Content from './Content'

const title = css`
  font-weight: bold;
`

const getIcon = (injectType: LogType): IconName => {
  switch (injectType) {
    case 'INJECT':
      return 'info-sign'
    case 'CUSTOM_INJECT':
      return 'info-sign'
    case 'EMAIL':
      return 'envelope'
    case 'TOOL':
      return 'console'
    case 'FORM':
      return 'form'
    default:
      throw new Error(`unknown channel type: ${injectType}`)
  }
}

const getTitle = (actionLog: ActionLog): string => {
  switch (actionLog.type) {
    case 'INJECT':
      return (actionLog.details as InjectDetails).inject.organization
    case 'CUSTOM_INJECT':
      return ''
    case 'EMAIL':
      return (actionLog.details as EmailDetails).sender.address
    case 'TOOL':
      return (actionLog.details as ToolDetails).tool.name
    case 'FORM':
      return (actionLog.details as QuestionnaireDetails).title
    default:
      throw new Error(`unknown channel type: ${actionLog.type}`)
  }
}

// TODO: ellipsize for too long messages, expand onInspect
interface InjectMessageProps {
  actionLog: ActionLog
  exerciseId: string
  teamId: string
  onInspect?: MouseEventHandler
  fill?: boolean
  inInstructor: boolean
}

const InjectMessage: FC<InjectMessageProps> = ({
  actionLog,
  exerciseId,
  teamId,
  onInspect,
  fill,
  inInstructor,
}) => {
  // this ensures the message is rendered as 'not read' the first time it's rendered
  // eslint-disable-next-line react-hooks/exhaustive-deps
  const initialReadReceipt = useMemo(() => actionLog.readReceipt, [])

  const [mutate] = useWriteReadReceipt({
    variables: { actionLogId: actionLog.id },
  })
  useEffect(() => {
    if (!actionLog.readReceipt) {
      mutate()
    }
  }, [actionLog.readReceipt, mutate])

  return (
    <Message
      fill={fill}
      header={
        <>
          <HeaderItem>
            <Icon
              className={Classes.TEXT_MUTED}
              style={{ paddingLeft: '0.25rem' }}
              icon={getIcon(actionLog.type)}
            />
            <span className={title}>{getTitle(actionLog)}</span>
          </HeaderItem>
          <HeaderItem>
            <Timestamp
              minimal
              datetime={new Date(actionLog.timestamp || 0)}
              isRead={initialReadReceipt !== null}
            />
            {onInspect && (
              <Button minimal icon='fullscreen' onClick={onInspect} />
            )}
          </HeaderItem>
        </>
      }
    >
      <Content
        actionLog={actionLog}
        teamId={teamId}
        exerciseId={exerciseId}
        inInstructor={inInstructor}
      />
    </Message>
  )
}

export default InjectMessage
