import ContentArea from '@/components/ContentArea'
import FileArea from '@/components/FileArea'
import {
  Button,
  ButtonGroup,
  Divider,
  FormGroup,
  Label,
  NonIdealState,
} from '@blueprintjs/core'
import { css } from '@emotion/css'
import type { Channel, FileInfo } from '@inject/graphql/fragment-types'
import { useTypedMutation, useTypedQuery } from '@inject/graphql/graphql'
import { SendCustomInject } from '@inject/graphql/mutations'
import { GetExercise, GetExerciseChannels } from '@inject/graphql/queries'
import CenteredSpinner from '@inject/shared/components/CenteredSpinner'
import ErrorMessage from '@inject/shared/components/ErrorMessage'
import { notify } from '@inject/shared/notification/engine'
import notEmpty from '@inject/shared/utils/notEmpty'
import type { Dispatch, SetStateAction } from 'react'
import { useEffect, useMemo, useState } from 'react'
import { useParams } from 'react-router-dom'
import ChannelSelector from './ChannelSelector'
import OverlayForm from './OverlayForm'
import TeamSelector from './TeamSelector'

export const MainDrawer = css`
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
`

const footer = css`
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  flex-direction: row-reverse;
  gap: 0.5rem;
`

const body = css`
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex-grow: 1;
`

interface InjectComposerProps {
  teamId?: string
  exerciseId: string
  setIsOpen: Dispatch<SetStateAction<boolean>>
}

const InjectForm = ({ teamId, exerciseId, setIsOpen }: InjectComposerProps) => {
  const [{ fetching: loading }, mutate] = useTypedMutation(SendCustomInject)
  const { channelId } = useParams()

  const [selectedTeamIds, setSelectedTeamIds] = useState<string[]>(
    [teamId].filter(notEmpty)
  )

  const [{ data, fetching: getExerciseLoading, error }] = useTypedQuery({
    query: GetExercise,
    variables: { exerciseId },
  })
  const [selectedChannel, setSelectedChannel] = useState<Channel | null>(null)
  const [{ data: dataChannels, fetching: getChannelsLoading }] = useTypedQuery({
    query: GetExerciseChannels,
    variables: { exerciseId },
  })
  const channels = useMemo(
    () =>
      dataChannels?.exerciseChannels?.filter(
        channel => channel?.type === 'INFO'
      ) || [],
    [dataChannels?.exerciseChannels]
  )
  useEffect(() => {
    if (channels.length === 1) {
      setSelectedChannel(channels[0])
    }
    if (channelId) {
      setSelectedChannel(
        channels.find(channel => channel.id === channelId) ?? null
      )
    }
  }, [channelId, channels])

  const [content, setContent] = useState('')
  const [isOverlay, setIsOverlay] = useState(false)
  const [duration, setDuration] = useState<number | undefined>()
  const [fileInfo, setFileInfo] = useState<FileInfo>()

  if (getExerciseLoading || getChannelsLoading) {
    return <CenteredSpinner />
  }
  if (error) {
    return (
      <ErrorMessage>
        <h1>Error occurred!</h1>
        <p>{error.message}</p>
      </ErrorMessage>
    )
  }
  if (!data?.exerciseId) {
    return (
      <NonIdealState
        icon='low-voltage-pole'
        title='No data'
        description='Please wait for the data to come in'
      />
    )
  }
  const teams = data.exerciseId.teams.filter(notEmpty)

  const onSend = () => {
    if (selectedTeamIds.length === 0) {
      notify('Select at least one team', {
        intent: 'danger',
      })
      return
    }
    if (!selectedChannel) {
      notify('Select a channel', {
        intent: 'danger',
      })
      return
    }
    if (!content && !fileInfo) {
      notify('Add a message or an attachment', {
        intent: 'danger',
      })
      return
    }
    if (isOverlay && !duration) {
      notify('Set the duration', { intent: 'danger' })
      return
    }

    mutate({
      customInjectInput: {
        teamIds: selectedTeamIds,
        content,
        exerciseId,
        fileId: fileInfo?.id ?? null,
        channelId: selectedChannel.id,
        overlay:
          isOverlay && duration
            ? {
                duration,
              }
            : null,
      },
    })
      .then(() => {
        setIsOpen(false)
      })
      .catch(err => {
        notify(err.message, { intent: 'danger' })
      })
  }

  return (
    <div className={MainDrawer}>
      {/* using Label directly messes up the MultiSelect */}
      <FormGroup fill label={<>Teams</>} labelFor='create-user-tags'>
        <TeamSelector
          teams={teams}
          selectedTeamIds={selectedTeamIds}
          setSelectedTeamIds={setSelectedTeamIds}
        />
      </FormGroup>

      {channels.length > 1 && (
        <Label style={{ width: '100%' }}>
          Channel
          <ChannelSelector
            channels={channels}
            selectedChannel={selectedChannel}
            setSelectedChannel={setSelectedChannel}
          />
        </Label>
      )}

      <OverlayForm
        isOverlay={isOverlay}
        setIsOverlay={setIsOverlay}
        duration={duration}
        setDuration={setDuration}
      />

      <Divider style={{ margin: '0.5rem 0' }} />

      <div className={body}>
        <ContentArea content={content} setContent={setContent} />
        <FileArea
          exerciseId={exerciseId}
          fileInfo={fileInfo}
          setFileInfo={setFileInfo}
          teamId={selectedTeamIds[0]}
        />
      </div>

      <Divider style={{ margin: '0.5rem 0' }} />

      <div className={footer}>
        <FormGroup disabled={loading} style={{ margin: '0' }}>
          <ButtonGroup>
            <Button icon='trash' onClick={() => setIsOpen(false)}>
              Discard
            </Button>
            <Button
              type='submit'
              rightIcon='send-message'
              onClick={onSend}
              loading={loading}
            >
              Send
            </Button>
          </ButtonGroup>
        </FormGroup>
      </div>
    </div>
  )
}

export default InjectForm
