import { Anchor, Box, Button, Card, Divider, Group, Loader, Modal, notifier, Stack, Typography } from '@tidbcloud/uikit'
import { IconAlertTriangle, IconCheckCircle, IconXCircle } from '@tidbcloud/uikit/icons'
import { useMount } from 'ahooks'
import { useMemo, useRef, useState } from 'react'
import { useFormContext } from 'react-hook-form'
import { useHistory, useParams } from 'react-router-dom'

import { Commonv1beta1ServicePlan } from 'dbaas/services/api-clients/v2025/tidb-management/v1beta2/interface'
import {
  useCreateCheckImportSourceTask,
  useCreateImportIntoTask,
  useGetCheckImportSourceTask
} from 'dbaas/services/dataflow'
import { getErrorMessage, UnexpectedError } from 'dbaas/services/errorCodes'
import { eventTracking, MixpanelEvents } from 'dbaas/utils/tracking'

import { normalizeImportSource } from './helper'
import { CSVConfigurationForPremiumImport, LearnHowMappingWorks } from './shared'
import { ImportFromCloudFormData } from './types'

const PRECHECK_POLL_INTERVAL = 2000

export const Precheck = ({ onCancel, onGoPrev }: { onCancel: () => void; onGoPrev: () => void }) => {
  const { id: tidbId = '' } = useParams<{ id: string }>()
  const history = useHistory()
  const methods = useFormContext<ImportFromCloudFormData>()
  const createImportIntoTask = useCreateImportIntoTask()
  const createPrecheckTask = useCreateCheckImportSourceTask()
  const sourceUri = methods.watch('source_uri')
  const [showCsvFormat, setShowCsvFormat] = useState(false)
  const [precheckTaskId, setPrecheckTaskId] = useState('')
  const [precheckSetupError, setPrecheckSetupError] = useState<Error | null>(null)
  const csvFormat = methods.watch('csv_format')
  const followNamingConventions = methods.watch('use_tidb_dumpling_naming_conventions')
  const startedRef = useRef(false)
  const precheckTaskQuery = useGetCheckImportSourceTask(tidbId, precheckTaskId, {
    query: {
      enabled: Boolean(tidbId && precheckTaskId),
      refetchOnWindowFocus: false,
      refetchInterval: (data) => {
        if (!data) {
          return PRECHECK_POLL_INTERVAL
        }

        return data.status === 'ENUM_RUNNING' ? PRECHECK_POLL_INTERVAL : false
      }
    }
  })
  const precheckData = precheckTaskQuery.data
  const precheckTaskError =
    precheckData?.success === false ? new Error(precheckData.errorMsg || UnexpectedError) : precheckSetupError
  const precheckError = precheckTaskError || createPrecheckTask.error || precheckTaskQuery.error
  const isPrecheckLoading =
    !precheckError &&
    (createPrecheckTask.isLoading ||
      (!!precheckTaskId && (precheckTaskQuery.isLoading || precheckTaskQuery.data?.status === 'ENUM_RUNNING')))
  const isPrecheckSuccess = Boolean(precheckData && !isPrecheckLoading && !precheckError)

  const onSubmit = async (data: ImportFromCloudFormData) => {
    try {
      const { importId } = await createImportIntoTask.mutateAsync({
        tidbId,
        data: {
          username: data.username,
          password: data.password,
          groupKey: data.job_name,
          creationDetails: {
            importOptions: {
              csvFormat: {
                ...data.csv_format
              }
            },
            source: normalizeImportSource(data)!,
            targetTableInfos: precheckData?.tableMetas
          }
        }
      })
      notifier.success('Import job created successfully')
      history.push(`/tidbs/${tidbId}/imports?importId=${importId}`)
    } catch {
      eventTracking(MixpanelEvents.TidbImport.Create.RequestFailed, {
        servicePlan: Commonv1beta1ServicePlan.Premium
      })
    }
  }

  useMount(() => {
    if (startedRef.current) {
      return
    }

    startedRef.current = true

    const runPrecheck = async () => {
      const data = methods.getValues()
      const source = normalizeImportSource(data)

      if (!source) {
        setPrecheckSetupError(new Error(UnexpectedError))
        return
      }

      try {
        const { taskId } = await createPrecheckTask.mutateAsync({
          tidbId,
          data: {
            source,
            tableMetas: followNamingConventions ? undefined : data.target_table_infos
          }
        })

        if (!taskId) {
          setPrecheckSetupError(new Error(UnexpectedError))
          return
        }

        setPrecheckSetupError(null)
        setPrecheckTaskId(taskId)
      } catch {}
    }

    void runPrecheck()
  })

  const totalObjects = precheckData?.totalScannedObjects || 0
  const hasScannedObjects = totalObjects > 0
  const isEmpty = useMemo(() => {
    return !precheckData?.totalScannedObjects || precheckData.tableMetas?.every((i) => !i.filesWildcard)
  }, [precheckData])

  return (
    <Card p={24}>
      <Stack component="form" onSubmit={methods.handleSubmit(onSubmit)}>
        <Typography variant="title-lg">Pre-check</Typography>

        <Typography>
          Source Files URI: <b>{sourceUri}</b>
        </Typography>

        <LearnHowMappingWorks />

        <Card withBorder={false} bg="carbon.2">
          <Group gap={8} wrap="nowrap" align="flex-start">
            {isPrecheckLoading && (
              <>
                <Loader size="xs" />
                <Typography c="carbon.8" variant="label-md">
                  We are scanning files in your source, please wait...
                </Typography>
              </>
            )}
            {precheckError && (
              <>
                <IconXCircle size={18} color="red" sx={{ flexShrink: 0 }} />
                <Typography c="carbon.8" variant="label-md">
                  Failed to scan files,{' '}
                  <span dangerouslySetInnerHTML={{ __html: getErrorMessage(precheckError, true) }} />.
                </Typography>
              </>
            )}
            {isPrecheckSuccess && (
              <>
                {hasScannedObjects ? (
                  <IconCheckCircle size={18} c="green.7" sx={{ flexShrink: 0 }} />
                ) : (
                  <IconAlertTriangle size={18} c="yellow" sx={{ flexShrink: 0 }} />
                )}
                <Typography c="carbon.8" variant="label-md">
                  Scan completed, found {totalObjects} object{totalObjects !== 1 ? 's' : ''} in total.
                </Typography>
              </>
            )}
          </Group>
        </Card>

        {isPrecheckSuccess && !!precheckData?.tableMetas?.length && (
          <>
            <Divider mx={-24} />

            <Group justify="space-between">
              <Typography variant="title-lg">Scan Result</Typography>

              <Modal opened={showCsvFormat} onClose={() => setShowCsvFormat(false)} title="CSV Configuration" size="lg">
                <CSVConfigurationForPremiumImport
                  defaultValues={csvFormat}
                  onCancel={() => setShowCsvFormat(false)}
                  onApply={(data) => {
                    methods.setValue('csv_format', data)
                    setShowCsvFormat(false)
                  }}
                />
              </Modal>
            </Group>

            <Card>
              <Card.Section bg="carbon.2" p={16}>
                <Group justify="space-evenly">
                  <Typography sx={{ flex: 2 }}>Source File</Typography>
                  <Typography sx={{ flex: 1 }}>Target Table</Typography>
                </Group>
              </Card.Section>
              <Card.Section mah={600} sx={{ overflowY: 'auto' }}>
                {precheckData.tableMetas?.map((i) => (
                  <Box px={16} py={12} key={i.filesWildcard}>
                    <Group justify="space-evenly" wrap="nowrap">
                      <Typography sx={{ flex: 2 }} truncate title={i.filesWildcard}>
                        {i.filesWildcard || 'No items'}
                      </Typography>
                      <Typography sx={{ flex: 1 }} truncate title={`${i.database}.${i.table}`}>
                        {i.database}.{i.table}
                      </Typography>
                    </Group>
                  </Box>
                ))}
              </Card.Section>
            </Card>

            <Typography variant="body-md" c="carbon.7" mt={-8}>
              If your source files are in the CSV format, you can{' '}
              <Anchor fz={13} onClick={() => setShowCsvFormat(true)}>
                edit CSV configuration here.
              </Anchor>
            </Typography>
          </>
        )}

        <Divider mx={-24} />

        <Group justify="flex-end">
          <Button variant="default" onClick={onCancel}>
            Cancel
          </Button>
          <Button variant="default" onClick={onGoPrev}>
            Previous
          </Button>

          <Button type="submit" disabled={!isPrecheckSuccess || isEmpty} loading={createImportIntoTask.isLoading}>
            Start Import
          </Button>
        </Group>
      </Stack>
    </Card>
  )
}
