import {
  ActionIcon,
  Alert,
  Badge,
  Box,
  Card,
  CopyButton,
  Grid,
  Group,
  Loader,
  Menu,
  notifier,
  Progress,
  Stack,
  Typography
} from '@tidbcloud/uikit'
import { PropertyCard } from '@tidbcloud/uikit/biz'
import { IconAlertCircle, IconCheck, IconCopy01, IconDotsHorizontal } from '@tidbcloud/uikit/icons'
import { capitalize } from 'lodash-es'
import prettyMilliseconds from 'pretty-ms'
import { useMemo } from 'react'
import { useParams } from 'react-router-dom'

import { humanByteSize } from 'common/services/prommetric'
import { HeroComponent, isHeroQueryReady } from 'dbaas/components/Measurement'
import { StatusBadge, StatusVariantMap } from 'dbaas/components/StatusBadge'
import TimeComponent from 'dbaas/components/TimeComponent'
import { AccessCheck } from 'dbaas/contexts/access-control'
import { ImportStatus } from 'dbaas/features/Import/ImportStatus'
import { CloudProviderConst, CloudStorageLabelConst } from 'dbaas/features/Project'
import { TiDBPageShell } from 'dbaas/screens/NextGen/tidb-mgmt-container/shared/TiDBPageShell'
import { useCancelImportIntoTask, useGetImportIntoTask } from 'dbaas/services/dataflow'
import {
  Adminapiv1beta2ImportSourceTypeEnum,
  V1beta2ImportIntoSubTask,
  V1beta2ImportIntoTask,
  V1beta2ImportStateEnum,
  V1beta2ImportSubTaskStatusEnum
} from 'dbaas/services/dataflow/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import { formatNumber } from 'dbaas/utils/numberFormat'
import { MixpanelEvents } from 'dbaas/utils/tracking'

import { getImportFileTypeLabel } from './fileType'

const PremiumImportSummary = ({ data }: { data: V1beta2ImportIntoTask }) => {
  const providerMap = {
    [Adminapiv1beta2ImportSourceTypeEnum.ENUM_S3]: CloudProviderConst.AWS,
    [Adminapiv1beta2ImportSourceTypeEnum.ENUM_OSS]: CloudProviderConst.ALICLOUD,
    [Adminapiv1beta2ImportSourceTypeEnum.ENUM_AZURE_BLOB]: CloudProviderConst.AZURE
  }

  return (
    <>
      <PropertyCard.Item label="ID">{data.importId}</PropertyCard.Item>
      {data.state && (
        <PropertyCard.Item label="Status">
          <ImportStatus
            status={data.state}
            error={
              data.state === V1beta2ImportStateEnum.ENUM_FAILED
                ? [data.message, data.subtasks?.[0]?.resultMessage].filter(Boolean).join(' ')
                : ''
            }
            withinPortal
          />
        </PropertyCard.Item>
      )}

      {data.creationDetails && (
        <>
          {data.creationDetails?.source?.type && (
            <PropertyCard.Item label="Storage Provider">
              {CloudStorageLabelConst[providerMap[data.creationDetails.source.type]]}
            </PropertyCard.Item>
          )}
          {data.creationDetails?.source?.s3?.uri && (
            <PropertyCard.Item label="Source File URI">{data.creationDetails.source.s3.uri}</PropertyCard.Item>
          )}
          {data.creationDetails?.source?.azureBlob?.uri && (
            <PropertyCard.Item label="Folder URI">{data.creationDetails.source.azureBlob.uri}</PropertyCard.Item>
          )}
          {data.creationDetails?.source?.s3?.accessKey?.id && (
            <PropertyCard.Item label="S3 Access Key ID">
              {data.creationDetails.source.s3.accessKey.id.replace(/(.{4}).*(.{4})/, '$1****$2')}
            </PropertyCard.Item>
          )}
        </>
      )}

      {data.createTime && (
        <PropertyCard.Item label="Create Time">
          <TimeComponent time={data.createTime} />
        </PropertyCard.Item>
      )}

      {data.completeTime && (
        <PropertyCard.Item label="Complete Time">
          <TimeComponent time={data.completeTime} />
        </PropertyCard.Item>
      )}

      {data.creator && <PropertyCard.Item label="Creator">{data.creator}</PropertyCard.Item>}
    </>
  )
}

const ImportDetailPremium = () => {
  const { id: tidbId, importId } = useParams<{ id: string; importId: string }>()
  const { data, isLoading, isFetched, isError, refetch, error } = useGetImportIntoTask(tidbId, importId, {
    query: {
      refetchInterval(data) {
        if (
          [
            V1beta2ImportStateEnum.ENUM_CANCELED,
            V1beta2ImportStateEnum.ENUM_COMPLETED,
            V1beta2ImportStateEnum.ENUM_FAILED,
            V1beta2ImportStateEnum.ENUM_SCALING_UP
          ].includes(data?.state as any)
        ) {
          return false
        }

        return 1000
      }
    }
  })
  const cancelMutation = useCancelImportIntoTask()

  const canCancel = useMemo(() => {
    if (!data?.state) return false
    return [
      V1beta2ImportStateEnum.ENUM_PREPARING,
      V1beta2ImportStateEnum.ENUM_IMPORTING,
      V1beta2ImportStateEnum.ENUM_SCALING_UP
    ].includes(data.state as any)
  }, [data?.state])

  const handleCancel = async () => {
    try {
      await cancelMutation.mutateAsync({
        tidbId,
        importId,
        data: {
          reason: 'User cancelled'
        }
      })

      notifier.success('Import task cancelled successfully')
      refetch()
    } catch (e) {
      notifier.error(getErrorMessage(e, true))
    }
  }

  return (
    <TiDBPageShell
      title="Import Detail"
      headerProps={{
        withBack: true,
        rightSection: canCancel ? (
          <Menu position="bottom-end">
            <Menu.Target>
              <ActionIcon variant="default">
                <IconDotsHorizontal size={16} />
              </ActionIcon>
            </Menu.Target>
            <Menu.Dropdown miw={120}>
              <AccessCheck id="TidbxImportAction">
                {({ accessible }) => (
                  <Menu.Item
                    disabled={!accessible}
                    data-mp-event={MixpanelEvents.TidbImport.Cancel.ButtonClicked}
                    onClick={handleCancel}
                  >
                    Cancel
                  </Menu.Item>
                )}
              </AccessCheck>
            </Menu.Dropdown>
          </Menu>
        ) : null
      }}
      bodyProps={{
        style: {
          height: '100%'
        }
      }}
    >
      <HeroComponent ready={isHeroQueryReady({ isFetched, isError })} />
      {isLoading && <Loader size="xs" m="auto" />}
      {error && (
        <Alert color="red" title="Failed to fetch import task" icon={<IconAlertCircle />}>
          {getErrorMessage(error, true)}
        </Alert>
      )}
      {data && (
        <Group maw={1200} h="100%" mx="auto" justify="center" align="flex-start">
          <Card sx={{ flex: 1, minHeight: '100%' }} component={Stack}>
            <Typography variant="title-lg">Jobs</Typography>

            {data.subtasks?.map((task, index) => <SubtaskDetail key={index} task={task} />)}
          </Card>

          <Stack maw={400}>
            <PropertyCard title="Basic Information">
              <PremiumImportSummary data={data} />
            </PropertyCard>

            {data.totalSize && (
              <Card maw={400}>
                <Typography variant="label-lg" c="carbon.7" mb={8}>
                  Total size
                </Typography>
                <Typography variant="title-lg">{humanByteSize(parseInt(data.totalSize), false, 3)}</Typography>
              </Card>
            )}

            {data.subtasks && (
              <Card>
                <Typography variant="label-lg" c="carbon.7" mb={8}>
                  Total rows imported
                </Typography>
                <Typography variant="title-lg">
                  {formatNumber(
                    data.subtasks?.reduce((acc, curr) => acc + Number(curr.importedRows), 0),
                    0
                  )}
                </Typography>
              </Card>
            )}

            {data.createTime && data.completeTime && (
              <Card>
                <Typography variant="label-lg" c="carbon.7" mb={8}>
                  Total duration
                </Typography>
                <Typography variant="title-lg">
                  {prettyMilliseconds(new Date(data.completeTime).getTime() - new Date(data.createTime).getTime())}
                </Typography>
              </Card>
            )}
          </Stack>
        </Group>
      )}
    </TiDBPageShell>
  )
}

export default ImportDetailPremium

const SubtaskSteps = ['prevalidate', 'encode', 'merge-sort', 'ingest', 'post-process']

function SubtaskDetail({ task }: { task: V1beta2ImportIntoSubTask }) {
  const entries = useMemo(() => {
    const res: [string, string][] = []
    if (task.currentStepEta) {
      res.push(['Estimated time of step completion', `${task.currentStepEta} left`])
    }
    if (task.currentStepSpeed) {
      res.push(['Average Speed', task.currentStepSpeed])
    }
    if (task.currentStepProcessedDataSize && task.currentStepTotalSize) {
      res.push(['Bytes processed / Total', `${task.currentStepProcessedDataSize} / ${task.currentStepTotalSize}`])
    }

    return res
  }, [task])

  const currentStepIndex = SubtaskSteps.findIndex((i) => i === task.currentStep)
  const fileType = getImportFileTypeLabel(task.filesWildcard)

  return (
    <Card component={Stack} bg="carbon.2">
      <Group wrap="nowrap">
        <SubtaskStatus status={task.status!} />
        <SubtaskMapping from={task.filesWildcard!} to={`${task.database}.${task.table}`} />
      </Group>

      {task.status === 'ENUM_FAILED' && task.resultMessage && (
        <Alert color="red" icon={<IconAlertCircle />}>
          {task.resultMessage}
        </Alert>
      )}

      {task.status === 'ENUM_WARNING' && task.resultMessage && (
        <Alert color="yellow" icon={<IconAlertCircle />}>
          {task.resultMessage}
        </Alert>
      )}

      {task.currentStep && (
        <>
          <Stack gap={8}>
            <Typography variant="label-md">{`Step ${currentStepIndex + 1}/${SubtaskSteps.length}: ${capitalize(task.currentStep)}`}</Typography>

            {entries.length > 0 && (
              <Grid>
                {entries.map(([title, value]) => {
                  return (
                    <Grid.Col span={Math.ceil(12 / entries.length)} key={title}>
                      <Typography variant="label-md" c="carbon.7" mb={8}>
                        {title}
                      </Typography>
                      <Typography variant="body-lg" c="carbon.8">
                        {value}
                      </Typography>
                    </Grid.Col>
                  )
                })}
              </Grid>
            )}
          </Stack>

          <Group wrap="nowrap" grow gap={8}>
            {SubtaskSteps.map((step, index) => {
              const isFinished = currentStepIndex > index
              const isIncoming = currentStepIndex < index
              const isCurrent = currentStepIndex === index
              const value = (() => {
                if (isFinished) return 100
                if (isCurrent) return task.currentStepProgressPercent || 60 // default to 60% if running but no progress
                if (isIncoming) return 0
                return 0
              })()
              return (
                <Progress
                  color="peacock"
                  key={step}
                  value={value}
                  h={4}
                  styles={{ root: { backgroundColor: 'var(--mantine-color-carbon-4)' } }}
                />
              )
            })}
          </Group>
        </>
      )}

      <Group justify="flex-end" gap={8}>
        {fileType && (
          <Box sx={{ border: '1px solid var(--mantine-color-carbon-4)', borderRadius: 16, padding: '4px 10px' }}>
            <Typography fz={12}>{fileType}</Typography>
          </Box>
        )}
        <CopyButton value={task.jobId!}>
          {({ copied, copy }) => (
            <Group
              gap={8}
              sx={{ border: '1px solid var(--mantine-color-carbon-4)', borderRadius: 16, padding: '0px 8px' }}
            >
              <Typography fz={12}>Job ID: {task.jobId}</Typography>
              <ActionIcon variant="transparent" onClick={copy}>
                {copied ? <IconCheck /> : <IconCopy01 />}
              </ActionIcon>
            </Group>
          )}
        </CopyButton>
      </Group>
    </Card>
  )
}

function getSubstaskStatusLabel(status: V1beta2ImportSubTaskStatusEnum) {
  const statusLabelMap = {
    [V1beta2ImportSubTaskStatusEnum.ENUM_PENDING]: 'Pending',
    [V1beta2ImportSubTaskStatusEnum.ENUM_CANCELED]: 'Canceled',
    [V1beta2ImportSubTaskStatusEnum.ENUM_FAILED]: 'Failed',
    [V1beta2ImportSubTaskStatusEnum.ENUM_FINISHED]: 'Finished',
    [V1beta2ImportSubTaskStatusEnum.ENUM_RUNNING]: 'Running',
    [V1beta2ImportSubTaskStatusEnum.ENUM_WARNING]: 'Warning',
    [V1beta2ImportSubTaskStatusEnum.ENUM_UNSPECIFIED]: 'Unspecified'
  }
  return statusLabelMap[status] || 'Unknown'
}

function SubtaskStatus({ status }: { status: V1beta2ImportSubTaskStatusEnum }) {
  const StatusColorMap = {
    [V1beta2ImportSubTaskStatusEnum.ENUM_PENDING]: 'carbon',
    [V1beta2ImportSubTaskStatusEnum.ENUM_CANCELED]: 'carbon',
    [V1beta2ImportSubTaskStatusEnum.ENUM_FAILED]: 'red',
    [V1beta2ImportSubTaskStatusEnum.ENUM_FINISHED]: 'green',
    [V1beta2ImportSubTaskStatusEnum.ENUM_RUNNING]: 'peacock',
    [V1beta2ImportSubTaskStatusEnum.ENUM_WARNING]: 'yellow',
    [V1beta2ImportSubTaskStatusEnum.ENUM_UNSPECIFIED]: 'carbon'
  }
  const color = StatusColorMap[status] as any
  const variant = StatusVariantMap[color] ?? 'default'
  return <StatusBadge variant={variant} status={getSubstaskStatusLabel(status)} color={color} sx={{ flexShrink: 0 }} />
}

function SubtaskMapping({ from, to }: { from: string; to: string }) {
  return (
    <Group gap={8} wrap="nowrap">
      <Badge variant="default" color="carbon" bg="carbon.2" sx={{ flexShrink: 0 }}>
        From
      </Badge>
      <Typography truncate maw="50%" title={from}>
        {from}
      </Typography>
      <Badge variant="default" color="carbon" bg="carbon.2">
        To
      </Badge>
      <Typography truncate maw="30%" title={to}>
        {to}
      </Typography>
    </Group>
  )
}
