import {
  Alert,
  Button,
  Card,
  Divider,
  Group,
  Modal,
  notifier,
  Progress,
  Stack,
  Text,
  Typography
} from '@tidbcloud/uikit'
import { useMount } from 'ahooks'
import { capitalize } from 'lodash-es'
import { observer } from 'mobx-react'
import { Fragment, useEffect, useMemo, useRef, useState } from 'react'
import { useFormContext } from 'react-hook-form'

import { DmImportMode } from 'dbaas/features/DataMigration'
import type { EssentialDMFormData } from 'dbaas/screens/DataMigration/CreateDataMigrationEssential.types'
import type { EssentialStep1FormData } from 'dbaas/screens/DataMigration/steps/Step1/EssentialDMStep1'
import type { EssentialStep2FormData } from 'dbaas/screens/DataMigration/steps/Step2/EssentialDMStep2'
import {
  useMigrationServiceCancelPrecheck,
  useMigrationServiceGetPrecheck,
  useMigrationServicePrecheck
} from 'dbaas/services/api-clients/legacy/serverless'
import type { MigrationServicePrecheckBody } from 'dbaas/services/api-clients/legacy/serverless/interface'
import { PrecheckItemType } from 'dbaas/services/api-clients/legacy/serverless/interface/precheckItemType'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'
import { eventTracking } from 'dbaas/utils/tracking'

import CheckItem, { CheckItemProps } from './CheckItem'
import classes from './Step3.module.css'

export type EssentialStep3FormData = Pick<EssentialStep1FormData, 'name' | 'cluster_username' | 'cluster_password'> &
  Pick<EssentialStep2FormData, 'sources' | 'migration_mode' | 'full_instance_migrate' | 'precheckId' | 'import_mode'>

const Step3 = ({
  onCancel,
  onGoPrev,
  onFinish
}: {
  onFinish: () => void
  onCancel: () => void
  onGoPrev: () => void
}) => {
  const {
    store: { tenantData, activeProjectId, currentCluster }
  } = useStores()
  const { getValues, setValue, watch } = useFormContext<EssentialDMFormData>()
  const formData = getValues() as EssentialStep3FormData
  const precheckId = watch('precheckId')
  const cancelPrecheck = useMigrationServiceCancelPrecheck()
  const [canStopPolling, setCanStopPolling] = useState(false)
  const [modalOpen, setModalOpen] = useState(false)
  const { data: precheckData, refetch } = useMigrationServiceGetPrecheck(
    tenantData.id,
    activeProjectId,
    currentCluster?.id!,
    precheckId,
    {
      query: {
        enabled: Boolean(precheckId) && !canStopPolling,
        refetchInterval: 5000
      }
    }
  )
  const precheck = useMigrationServicePrecheck()
  const progressColor = useMemo(() => {
    if (precheckData?.status === 'finished') {
      return 'green'
    }
    if (precheckData?.status === 'failed') {
      return 'red'
    }
    if (precheckData?.status === 'running') {
      return 'peacock'
    }
    return 'gray'
  }, [precheckData])
  const totalCount = precheckData?.total ?? Infinity
  const successCount = precheckData?.success_cnt ?? 0
  const failCount = precheckData?.failed_cnt ?? 0
  const warnCount = precheckData?.warn_cnt ?? 0
  const completedCount = successCount + failCount + warnCount
  const percentage = Math.floor((completedCount / totalCount) * 100)
  const warningItems = useMemo(
    () => precheckData?.items?.filter((i) => i.status === 'warn').map((i) => i.desc!) ?? [],
    [precheckData]
  )
  const ignoredItemsRef = useRef<typeof warningItems>([])
  const hasImportModeWarning = precheckData?.items?.some(
    (i) => i.type === PrecheckItemType.PRECHECK_ITEM_TYPE_LIGHTNING_TABLE_EMPTY_CHECKING && i.status === 'warn'
  )
  const displayedCheckItems = precheckData?.items?.filter((i) => i.status !== 'success') ?? []

  if (percentage === 100 && !canStopPolling) {
    setCanStopPolling(true)
  }

  const onGoNextStep = async (shoudIgnoreWarningCheck?: boolean) => {
    if (!shoudIgnoreWarningCheck && ignoredItemsRef.current.length < warningItems.length) {
      setModalOpen(true)
      return
    }

    if (precheckData?.status === 'finished') {
      if (hasImportModeWarning) {
        setValue('import_mode', DmImportMode.Logical)
      }
      onFinish()
      return
    }

    await precheckAgain()
  }

  const precheckAgain = async () => {
    setModalOpen(false)

    const payload: MigrationServicePrecheckBody = {
      name: formData.name,
      sources: formData.sources,
      target: {
        user: formData.cluster_username,
        password: formData.cluster_password
      },
      mode: formData.migration_mode,
      full_instance_migration: formData.full_instance_migrate
    }

    const res = await precheck.mutateAsync({
      orgId: tenantData.id,
      projectId: activeProjectId,
      clusterId: currentCluster?.id!,
      data: payload
    })

    setValue('precheckId', res.id ?? '')
    refetch()
  }

  const onCancelPrecheck = async () => {
    try {
      await cancelPrecheck.mutateAsync({
        orgId: tenantData.id,
        projectId: activeProjectId,
        clusterId: currentCluster?.id!,
        id: precheckId
      })

      refetch()

      eventTracking('DataMigration job‘s precheck canceled')
    } catch (e) {
      notifier.error(getErrorMessage(e, true) || 'Failed to cancel the precheck task')
    }
  }

  useEffect(() => {
    setCanStopPolling(false)
  }, [precheckId])

  useMount(() => {
    eventTracking('Enter the step to pre check DataMigration job')
  })

  return (
    <Card withBorder shadow="none" p={0}>
      <Stack m={24}>
        <Typography variant="headline-sm">Pre-check Process</Typography>

        <div className="wd-flex wd-items-center wd-gap-8">
          <Progress color={progressColor} value={percentage} sx={{ flex: 1 }} />
          <b>{capitalize(precheckData?.status)}</b>
          <b>{percentage}%</b>
          {!['canceled', 'finished', 'failed'].includes(precheckData?.status!) && (
            <Button
              variant="default"
              onClick={onCancelPrecheck}
              loading={cancelPrecheck.isLoading}
              data-mp-event="mp-cancel-1691461016921"
            >
              Cancel
            </Button>
          )}
        </div>
        <p>
          Total {totalCount} items,{' '}
          <Typography span c="blue">
            {completedCount}
          </Typography>{' '}
          completed,{' '}
          <Typography span c="green">
            {successCount}
          </Typography>{' '}
          passed,{' '}
          <Typography span c="yellow">
            {warnCount}
          </Typography>{' '}
          with warning,{' '}
          <Typography span c="red">
            {failCount}
          </Typography>{' '}
          failed.
        </p>
      </Stack>

      <Divider />

      {displayedCheckItems.length > 0 && (
        <Stack m={24}>
          <Typography variant="headline-sm">Pre-check Result</Typography>

          <div>
            <Group
              gap={0}
              className={classes.resultHeader}
              sx={(theme) => ({ backgroundColor: theme.colors.carbon[2] })}
            >
              <b>Check Item</b>
              <b>Status</b>
            </Group>
            {displayedCheckItems.map((i) => (
              <Fragment key={i.desc}>
                <CheckItem
                  {...i}
                  status={i.status! as CheckItemProps['status']}
                  onIgnore={(desc) => {
                    ignoredItemsRef.current?.push(desc)
                  }}
                />
              </Fragment>
            ))}
          </div>
        </Stack>
      )}

      {hasImportModeWarning && (
        <Alert title="Warning" color="yellow" m={24}>
          In physical migration mode, the target tables requiring data migration must be empty. However,{' '}
          {
            precheckData?.items?.find(
              (i) => i.type === PrecheckItemType.PRECHECK_ITEM_TYPE_LIGHTNING_TABLE_EMPTY_CHECKING
            )?.reason
          }
          . Please go back to exclude these tables, or the migration will be performed in logical mode.
        </Alert>
      )}

      <Group justify="flex-end" m={24}>
        <Button variant="default" type="button" onClick={onCancel} data-mp-event="mp-cancel-1691461016922">
          Cancel
        </Button>

        <Button variant="outline" type="button" onClick={onGoPrev} data-mp-event="mp-previous-1691461016924">
          Previous
        </Button>

        <Button
          type="button"
          onClick={() => onGoNextStep()}
          loading={precheck.isLoading}
          data-mp-event="mp--1691461016926"
        >
          {precheckData?.status !== 'finished' ? 'Check Again' : 'Next'}
        </Button>
      </Group>

      <Modal
        opened={modalOpen}
        size="xl"
        centered
        title={
          <Text fw={700} fz={20}>
            Pre-check result exists warnings
          </Text>
        }
        onClose={() => setModalOpen(false)}
      >
        <Stack>
          <div>
            <p>You can:</p>
            <ul>
              <li>
                Click <b>Check Again</b> to operate according to warning details and pass all check items.
              </li>
              <li>
                Click <b>Ignore warnings</b> and go to the next step immediately. <b>Note</b> that ignoring all warnings
                may result in job failures or data inconsistencies.
              </li>
            </ul>
          </div>

          <Group justify="flex-end">
            <Button
              variant="default"
              type="button"
              loading={precheck.isLoading}
              onClick={precheckAgain}
              data-mp-event="mp-checkagain-1691461016928"
            >
              Check Again
            </Button>
            <Button
              variant="default"
              type="button"
              onClick={() => onGoNextStep(true)}
              data-mp-event="mp-ignorewarnings-1691461016930"
            >
              Ignore warnings
            </Button>
          </Group>
        </Stack>
      </Modal>
    </Card>
  )
}

export const EssentialDMStep3 = observer(Step3)
