import type { ResultOf, VariablesOf } from '@inject/graphql/graphql'
import { CreateThread } from '@inject/graphql/mutations'
import { notify } from '@inject/shared/notification/engine'
import { useCallback } from 'react'
import { useClient } from 'urql'
import type { OnSendEmailInput } from './typing'

type ThreadSubmissionProps = (
  | {
      // existing thread
      existingThreadId: string
      participantAddresses?: undefined
      bccAddresses?: undefined
      subject?: undefined
    }
  | {
      // new thread
      existingThreadId?: undefined
      participantAddresses: string[]
      subject: string | undefined
      bccAddresses?: string[]
    }
) & {
  exerciseId: string
  content?: string
  fileId?: string
  senderAddress: string
  onSendEmail: (input: OnSendEmailInput) => void
}

const useThreadSubmission = ({
  exerciseId,
  existingThreadId,
  participantAddresses,
  senderAddress,
  bccAddresses,
  subject,
  onSendEmail,
  content,
  fileId,
}: ThreadSubmissionProps) => {
  const client = useClient()

  const onSend = useCallback(async () => {
    if (existingThreadId === undefined) {
      if (participantAddresses.length < 2) {
        notify('Select at least two participants', {
          intent: 'danger',
        })
        return
      }
      if (!subject) {
        notify('Add a subject', {
          intent: 'danger',
        })
        return
      }
    }

    if (!senderAddress) {
      notify('Select a sender', {
        intent: 'danger',
      })
      return
    }
    if (!content && !fileId) {
      notify('Add a message or an attachment', {
        intent: 'danger',
      })
      return
    }

    if (existingThreadId !== undefined) {
      onSendEmail({ threadId: existingThreadId, allowActivateMilestone: true })
      return
    }

    await client
      .mutation<
        ResultOf<typeof CreateThread>,
        VariablesOf<typeof CreateThread>
      >(CreateThread, {
        exerciseId,
        participantAddresses,
        // false positive TS error
        subject: subject || '',
      })
      .toPromise()
      .then(({ data }) => {
        onSendEmail({
          threadId: data?.createThread?.thread?.id || '',
          allowActivateMilestone: true,
        })

        if (!bccAddresses) {
          return
        }

        bccAddresses.forEach(async bccAddress => {
          await client
            .mutation<
              ResultOf<typeof CreateThread>,
              VariablesOf<typeof CreateThread>
            >(CreateThread, {
              exerciseId,
              participantAddresses: [bccAddress, senderAddress],
              // false positive TS error
              subject: subject || '',
            })
            .toPromise()
            .then(({ data }) => {
              onSendEmail({
                threadId: data?.createThread?.thread?.id || '',
                allowActivateMilestone: false,
              })
            })
            .catch(err => {
              notify(err.message, {
                intent: 'danger',
              })
            })
        })
      })
      .catch(err => {
        notify(err.message, {
          intent: 'danger',
        })
      })
  }, [
    bccAddresses,
    client,
    content,
    exerciseId,
    existingThreadId,
    fileId,
    onSendEmail,
    participantAddresses,
    senderAddress,
    subject,
  ])

  return {
    onSend,
  }
}

export default useThreadSubmission
