import { useNavigate } from '@/router'
import { checkFileSize } from '@/utils'
import type { ButtonProps } from '@blueprintjs/core'
import {
  Button,
  ButtonGroup,
  Dialog,
  DialogBody,
  DialogFooter,
} from '@blueprintjs/core'
import { notify } from '@inject/shared/notification/engine'
import JSZip from 'jszip'
import type { FC, ReactNode } from 'react'
import { memo, useCallback, useState } from 'react'
import { DEFINITION_IMPORT_CONTENT } from '../assets/dialogContent'
import { GENERIC_CONTENT } from '../assets/generalContent'
import { clearDb } from '../indexeddb/operations'
import useEditorStorage from '../useEditorStorage'
import type { GitlabConfig } from '../useGitlabStorage'
import useGitlabStorage from '../useGitlabStorage'
import { loadDbData, loadEditorConfig } from '../zip/loadDefinitionZip'

interface DefinitionImportDialogProps {
  children: ReactNode
  openButtonProps: ButtonProps
  addDisabled: boolean
  onAdd: () => Promise<{ file?: File; config?: GitlabConfig } | undefined>
}

const DefinitionImportDialog: FC<DefinitionImportDialogProps> = ({
  children,
  openButtonProps,
  addDisabled,
  onAdd,
}) => {
  const [isOpen, setIsOpen] = useState(false)
  const [, setConfig] = useEditorStorage()
  const [, setGitlabConfig] = useGitlabStorage()
  const nav = useNavigate()

  const handleAdd = useCallback(async () => {
    const result = await onAdd()
    if (!result || !result.file || !checkFileSize(result.file)) {
      return
    }

    const data = new FormData()
    data.append('file', result.file)

    await clearDb()

    try {
      const zip = await new JSZip().loadAsync(result.file)
      const config = await loadEditorConfig(zip, result.config)
      const finalMilestoneId = await loadDbData(zip)
      const fileNames = result.config
        ? Object.keys(zip.files).filter(name => !name.endsWith('/'))
        : undefined

      setConfig({ ...config, finalMilestone: finalMilestoneId, fileNames })
      nav('/editor/create/introduction')
    } catch (error) {
      notify(`Failed to load definition: ${error}`, JSON.stringify(error), {
        intent: 'danger',
      })
      await clearDb()
      clearDb()
      setConfig({})
      setGitlabConfig(prev => ({
        ...prev,
        project: undefined,
        branchFrom: undefined,
      }))
    }
  }, [onAdd])

  return (
    <>
      <Button {...openButtonProps} onClick={() => setIsOpen(true)} />
      <Dialog
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        icon='import'
        title='Upload definition'
      >
        <DialogBody>
          <p>{DEFINITION_IMPORT_CONTENT}</p>
          {children}
        </DialogBody>
        <DialogFooter
          actions={
            <ButtonGroup>
              <Button
                onClick={() => setIsOpen(false)}
                icon='cross'
                text={GENERIC_CONTENT.buttons.cancel}
              />
              <Button
                disabled={addDisabled}
                onClick={() => handleAdd()}
                intent='primary'
                icon='plus'
                text={GENERIC_CONTENT.buttons.add}
              />
            </ButtonGroup>
          }
        />
      </Dialog>
    </>
  )
}

export default memo(DefinitionImportDialog)
