import { Card, Group, HoverCard, Loader, notifier, Progress, ScrollArea, Stack, Typography } from '@tidbcloud/uikit'
import { observer } from 'mobx-react'
import ms from 'ms'
import { useMemo, type ReactNode } from 'react'
import { Link, Redirect, useParams } from 'react-router-dom'

import { humanByteSize } from 'common/services/prommetric'
import TimeComponent from 'dbaas/components/TimeComponent'
import { getModeLabel } from 'dbaas/features/DataMigration'
import { DmJobStatus } from 'dbaas/features/DataMigration/JobStatus'
import { useMigrationServiceGetTask } from 'dbaas/services/api-clients/legacy/serverless'
import type { MigrationTask, SubTask } from 'dbaas/services/api-clients/legacy/serverless/interface'
import {
  ConnType,
  MigrationTaskState,
  SubTaskStep,
  TaskMode
} from 'dbaas/services/api-clients/legacy/serverless/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'

import { stageNameMapper } from '../utils'

import SelectedObjects from './SelectedObject'

const toNumber = (value?: string | number | null) => {
  if (typeof value === 'number') return value
  if (typeof value === 'string') return Number(value)
  return 0
}

const Property = ({ label, value }: { label: ReactNode; value: ReactNode }) => (
  <Group wrap="nowrap">
    <Typography variant="label-lg" miw={200}>
      {label}
    </Typography>
    <Typography variant="body-lg" sx={{ flex: 1 }} lh="30px">
      {value}
    </Typography>
  </Group>
)

const TaskProgress = ({
  progress,
  currentStep,
  step,
  error,
  descriptions
}: {
  progress?: string
  currentStep?: SubTaskStep
  step: SubTaskStep
  error?: string
  descriptions: string[]
}) => {
  const progressValue = useMemo(() => Math.min(Math.max(toNumber(progress), 0), 100), [progress])
  const isCurrent = currentStep === step
  const isSuccess = progressValue === 100
  const isError = Boolean(error) && isCurrent && !isSuccess
  const color = useMemo(() => {
    if (isSuccess && step !== SubTaskStep.STEP_SYNC) {
      return 'green'
    }
    if (isError) {
      return 'red'
    }
    if (isCurrent) {
      return 'peacock'
    }
    return 'gray'
  }, [isSuccess, isCurrent, isError, step])

  return (
    <Stack gap={8}>
      <Group justify="space-between">
        <Typography fw={600} fz={14}>
          {stageNameMapper[step]}
        </Typography>
        {step !== SubTaskStep.STEP_SYNC && <Typography fw={600} fz={14}>{`${progressValue}%`}</Typography>}
      </Group>

      <Progress value={progressValue} color={color} />

      <Group justify="space-between" align="flex-start" wrap="nowrap">
        <Stack gap={4} maw={'50%'}>
          {isError && (
            <Typography c="red" variant="body-md">
              {error}
            </Typography>
          )}
        </Stack>

        <Stack gap={0} maw={'50%'}>
          {descriptions.map((item) => (
            <Typography key={item} variant="body-md" ta="right">
              {item}
            </Typography>
          ))}
        </Stack>
      </Group>
    </Stack>
  )
}

const getTask = (task?: MigrationTask | null): SubTask | undefined => {
  if (!task?.sub_tasks || task.sub_tasks.length === 0) {
    return undefined
  }
  return task.sub_tasks[0]
}

const getConnectivityLabel = (connType?: ConnType) => {
  switch (connType) {
    case ConnType.PRIVATE_LINK:
      return 'Private endpoint'
    case ConnType.PUBLIC:
      return 'Public endpoint'
    default:
      return '-'
  }
}

const EssentialDmJobDetail = () => {
  const {
    store: { tenantData, activeProjectId, currentCluster }
  } = useStores()
  const { id, jobId } = useParams<{ id: string; jobId: string }>()

  const { data, isLoading, isError, error } = useMigrationServiceGetTask(tenantData.id, activeProjectId, id, jobId, {
    request: { timeout: 30 * 1000 },
    query: { refetchInterval: 30 * 1000 }
  })

  const task = getTask(data)

  const showFullMigrateProgress = data?.mode !== TaskMode.MODE_INCREMENTAL
  const showIncrementalProgress = data?.mode === TaskMode.MODE_ALL || data?.mode === TaskMode.MODE_INCREMENTAL

  const dumpDescriptions = useMemo(() => {
    const totalTables = toNumber(task?.dump_detail?.total_tables)
    const completedTables = toNumber(task?.dump_detail?.completed_tables)
    const finishedBytes = toNumber(task?.dump_detail?.finished_bytes)
    const bps = toNumber(task?.dump_detail?.bps)
    const descriptions: string[] = []
    if (finishedBytes > 0) {
      descriptions.push(`${humanByteSize(finishedBytes, false)} data exported`)
    }
    if (totalTables > 0) {
      descriptions.push(`${completedTables}/${totalTables} tables completed`)
    }
    if (bps > 0) {
      descriptions.push(`Throughput ${humanByteSize(bps, false)}/s`)
    }
    return descriptions
  }, [task?.dump_detail])

  const loadDescriptions = useMemo(() => {
    const totalBytes = toNumber(task?.load_detail?.total_bytes)
    const finishedBytes = toNumber(task?.load_detail?.finished_bytes)
    const percentage = totalBytes > 0 ? Math.min(100, Math.floor((finishedBytes / totalBytes) * 100)) : undefined
    const bps = toNumber(task?.load_detail?.bps)
    const descriptions: string[] = []

    if (finishedBytes > 0) {
      descriptions.push(
        `${humanByteSize(finishedBytes, false)} data imported` + (percentage !== undefined ? ` (${percentage}%)` : '')
      )
    }
    if (totalBytes > 0) {
      descriptions.push(`${humanByteSize(totalBytes, false)} total`)
    }
    if (bps > 0) {
      descriptions.push(`Throughput ${humanByteSize(bps, false)}/s`)
    }
    return descriptions
  }, [task?.load_detail])

  const syncDescriptions = useMemo(() => {
    const latency = toNumber(task?.sync_detail?.latency ?? '0') * 1000
    const checkpoint = task?.sync_detail?.checkpoint ?? ''
    const rps = toNumber(task?.sync_detail?.rps ?? '0')
    const descriptions: string[] = []

    descriptions.push(`Latency ${ms(latency)}`)
    if (checkpoint) {
      descriptions.push(`Checkpoint ${checkpoint}`)
    }
    if (rps) {
      descriptions.push(`Throughput ${rps} rows/s`)
    }
    return descriptions
  }, [task?.sync_detail])

  const status = task?.stage ?? data?.state ?? MigrationTaskState.CREATING
  const jobName = data?.name ?? '-'
  const jobIdValue = data?.id ?? jobId

  if (isLoading) {
    return <Loader size="xs" />
  }

  if (isError) {
    notifier.error(getErrorMessage(error, true), {
      autoClose: 3000
    })
    return <Redirect to={`/clusters/${currentCluster?.id}/data-migration`} />
  }

  return (
    <Group align="start" gap={24} wrap="nowrap">
      <Stack justify="flex-start" sx={{ flexBasis: 450, flexShrink: 0, flexGrow: 0 }}>
        <Card withBorder shadow="none">
          <Stack gap={12}>
            <Typography variant="headline-sm">Summary</Typography>
            <Property label="Name" value={jobName} />
            <Property label="Job ID" value={jobIdValue} />
            <Property
              label="Status"
              value={
                <Group>
                  <DmJobStatus status={status!} error={task?.error_msg} />
                </Group>
              }
            />
            <Property label="Mode" value={getModeLabel(data?.mode)} />
            <Property
              label="Data Source"
              value={
                <Group>
                  <Typography variant="body-lg">MySQL</Typography>
                  <HoverCard withArrow shadow="md">
                    <HoverCard.Target>
                      <a>Details</a>
                    </HoverCard.Target>

                    <HoverCard.Dropdown>
                      <Stack gap={0}>
                        <Property
                          label="Connectivity"
                          value={getConnectivityLabel(task?.source?.conn_profile?.conn_type)}
                        />
                        {task?.source?.conn_profile?.endpoint_id && (
                          <Property label="Endpoint ID" value={task.source.conn_profile.endpoint_id} />
                        )}
                        <Property label="Hostname or IP address" value={task?.source?.conn_profile?.host ?? '-'} />
                        <Property label="Port" value={task?.source?.conn_profile?.port ?? '-'} />
                        <Property label="User" value={task?.source?.conn_profile?.user ?? '-'} />
                      </Stack>
                    </HoverCard.Dropdown>
                  </HoverCard>
                </Group>
              }
            />
            <Property
              label="Data Target"
              value={
                <Group>
                  <Typography variant="body-lg">TiDB</Typography>
                  <HoverCard withArrow shadow="md">
                    <HoverCard.Target>
                      <a>Details</a>
                    </HoverCard.Target>

                    <HoverCard.Dropdown>
                      <Stack gap={0}>
                        <Property label="Type" value="TiDB Cloud" />
                        <Property label="Region" value={currentCluster?.serverless?.region.displayName ?? '-'} />
                        <Property
                          label="Name"
                          value={
                            currentCluster?.id ? (
                              <Link to={`/clusters/${currentCluster.id}/overview`}>
                                {currentCluster?.displayName ?? currentCluster?.id}
                              </Link>
                            ) : (
                              '-'
                            )
                          }
                        />
                        <Property label="ID" value={currentCluster?.id ?? '-'} />
                        <Property label="Port" value={currentCluster?.serverless?.endpoints?.public?.port ?? '-'} />
                        <Property label="User" value={data?.target_user ?? '-'} />
                      </Stack>
                    </HoverCard.Dropdown>
                  </HoverCard>
                </Group>
              }
            />

            <Property
              label="Migration Objects"
              value={
                task?.source?.ba_rules?.do_dbs?.length || task?.source?.ba_rules?.do_tables?.length ? (
                  <HoverCard withArrow shadow="md" width={300}>
                    <HoverCard.Target>
                      <a>Details</a>
                    </HoverCard.Target>

                    <HoverCard.Dropdown>
                      <ScrollArea.Autosize mah={300}>
                        <SelectedObjects rules={task?.source?.ba_rules} />
                      </ScrollArea.Autosize>
                    </HoverCard.Dropdown>
                  </HoverCard>
                ) : (
                  'All'
                )
              }
            />

            {task?.source?.binlog_gtid && <Property label="Start Position" value={task.source.binlog_gtid} />}
            {task?.source?.binlog_name && typeof task?.source?.binlog_pos === 'number' && (
              <Property label="Start Position" value={`${task.source.binlog_name}_${task.source.binlog_pos}`} />
            )}

            {data?.create_time && <Property label="Creation Time" value={<TimeComponent time={data.create_time} />} />}
          </Stack>
        </Card>
      </Stack>

      <Stack justify="flex-start" style={{ flexGrow: 1 }}>
        <Card withBorder shadow="none">
          <Stack>
            <Typography variant="headline-sm">Progress</Typography>
            {data?.state !== MigrationTaskState.CREATING && task ? (
              <>
                {showFullMigrateProgress && (
                  <>
                    {task.dump_detail && (
                      <TaskProgress
                        currentStep={task?.current_step}
                        step={SubTaskStep.STEP_DUMP}
                        progress={String(task?.dump_detail?.progress ?? '0')}
                        error={task?.error_msg}
                        descriptions={dumpDescriptions}
                      />
                    )}

                    {task.load_detail && (
                      <TaskProgress
                        currentStep={task?.current_step}
                        step={SubTaskStep.STEP_LOAD}
                        progress={String(task?.load_detail?.progress ?? '0')}
                        error={task?.error_msg}
                        descriptions={loadDescriptions}
                      />
                    )}
                  </>
                )}

                {showIncrementalProgress && task.sync_detail && (
                  <TaskProgress
                    currentStep={task?.current_step}
                    step={SubTaskStep.STEP_SYNC}
                    progress={task?.current_step === SubTaskStep.STEP_SYNC ? '100' : '0'}
                    error={task?.error_msg}
                    descriptions={syncDescriptions}
                  />
                )}
              </>
            ) : (
              <Typography c="carbon.6" variant="body-md">
                Progress details will appear once the migration task starts running.
              </Typography>
            )}
          </Stack>
        </Card>
      </Stack>
    </Group>
  )
}

export default observer(EssentialDmJobDetail)
