import { Card, Group, HoverCard, Loader, notifier, Progress, ScrollArea, Stack, Typography } from '@tidbcloud/uikit'
import { PropertyCard } from '@tidbcloud/uikit/biz'
import { capitalize } from 'lodash-es'
import { observer } from 'mobx-react'
import ms from 'ms'
import { useMemo } from 'react'
import { Redirect, useParams } from 'react-router-dom'

import { humanByteSize } from 'common/services/prommetric'
import { HeroComponent, isHeroQueryReady } from 'dbaas/components/Measurement'
import TimeComponent from 'dbaas/components/TimeComponent'
import { getModeLabel } from 'dbaas/features/DataMigration'
import { DmJobStatus } from 'dbaas/features/DataMigration/JobStatus'
import { useSharedTiDBContext } from 'dbaas/screens/NextGen/tidb-mgmt-container/shared/tidb-context'
import { useGetPremiumMigration } from 'dbaas/services/dataflow'
import { PremiumDMSubTaskStep, V1beta2PremiumDMTaskMode } from 'dbaas/services/dataflow/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'

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 TaskProgress = ({
  progress,
  currentStep,
  step,
  error,
  descriptions
}: {
  progress?: number
  currentStep?: PremiumDMSubTaskStep
  step: PremiumDMSubTaskStep
  error?: string
  descriptions: string[]
}) => {
  const isCurrent = currentStep === step
  const isSuccess = progress === 100
  const isError = Boolean(error) && isCurrent && !isSuccess
  const color = useMemo(() => {
    if (isSuccess && step !== PremiumDMSubTaskStep.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 as any]}
        </Typography>
        {step !== PremiumDMSubTaskStep.SYNC && <Typography fw={600} fz={14}>{`${progress ?? 0}%`}</Typography>}
      </Group>

      <Progress value={progress ?? 0} color={color} />

      <Group justify="space-between" align="flex-start" wrap="nowrap">
        <Stack gap={4} maw={'50%'}>
          {isError && (
            <Typography color="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 PremiumDmJobDetail = () => {
  const tidb = useSharedTiDBContext()
  const { id, jobId } = useParams<{ id: string; jobId: string }>()

  const { data, isLoading, isFetched, isError, error } = useGetPremiumMigration(id, jobId, {
    request: { timeout: 30 * 1000 },
    query: { refetchInterval: 5 * 1000 }
  })

  const task = data?.sub_tasks?.[0]

  const showFullMigrateProgress =
    data?.mode === V1beta2PremiumDMTaskMode.ALL || data?.mode === V1beta2PremiumDMTaskMode.MODE_UNSPECIFIED
  const showIncrementalProgress =
    data?.mode === V1beta2PremiumDMTaskMode.ALL || data?.mode === V1beta2PremiumDMTaskMode.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 > 0) {
      descriptions.push(`Throughput ${rps} rows/s`)
    }
    return descriptions
  }, [task?.sync_detail])

  const status = data?.state
  const jobName = data?.display_name ?? '-'
  const jobIdValue = data?.migration_id ?? jobId
  const hero = <HeroComponent ready={isHeroQueryReady({ isFetched, isError })} />

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

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

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

                  <HoverCard.Dropdown maw={500}>
                    <Stack gap={8}>
                      <PropertyCard.Item label="Connectivity">
                        {capitalize(task?.source?.conn_profile?.conn_type)}
                      </PropertyCard.Item>
                      {task?.source?.conn_profile?.sink_endpoint_id && (
                        <PropertyCard.Item label="Private Endpoint">
                          {task.source.conn_profile.privatelink_info?.endpoint_name ??
                            task.source.conn_profile.sink_endpoint_id}
                        </PropertyCard.Item>
                      )}
                      {task?.source?.conn_profile?.privatelink_info?.endpoint_address && (
                        <PropertyCard.Item label="Private Endpoint Address">
                          {task.source.conn_profile.privatelink_info.endpoint_address}
                        </PropertyCard.Item>
                      )}
                      <PropertyCard.Item label="Hostname or IP address">
                        {task?.source?.conn_profile?.host ?? '-'}
                      </PropertyCard.Item>
                      <PropertyCard.Item label="Port">{task?.source?.conn_profile?.port ?? '-'}</PropertyCard.Item>
                      <PropertyCard.Item label="User">{task?.source?.conn_profile?.user ?? '-'}</PropertyCard.Item>
                    </Stack>
                  </HoverCard.Dropdown>
                </HoverCard>
              </Group>
            </PropertyCard.Item>
            <PropertyCard.Item label="Data Target">
              <Group>
                <Typography variant="body-lg">TiDB</Typography>
                <HoverCard withArrow shadow="md">
                  <HoverCard.Target>
                    <a>Details</a>
                  </HoverCard.Target>

                  <HoverCard.Dropdown>
                    <Stack gap={8}>
                      <PropertyCard.Item label="Type">TiDB Cloud</PropertyCard.Item>
                      <PropertyCard.Item label="Region">{tidb?.regionDisplayName ?? '-'}</PropertyCard.Item>
                      <PropertyCard.Item label="Name">{tidb?.displayName ?? tidb?.tidbId ?? '-'}</PropertyCard.Item>
                      <PropertyCard.Item label="ID">{tidb?.tidbId ?? '-'}</PropertyCard.Item>
                      <PropertyCard.Item label="User">{data?.target_user ?? '-'}</PropertyCard.Item>
                    </Stack>
                  </HoverCard.Dropdown>
                </HoverCard>
              </Group>
            </PropertyCard.Item>

            <PropertyCard.Item label="Migration Objects">
              {task?.source?.premium_migration_rules?.length ? (
                <HoverCard withArrow shadow="md" width={400}>
                  <HoverCard.Target>
                    <a>Details</a>
                  </HoverCard.Target>

                  <HoverCard.Dropdown>
                    <ScrollArea.Autosize mah={300}>
                      <SelectedObjects
                        rules={{
                          do_tables: task?.source?.premium_migration_rules?.map((i) => ({
                            schema: i.source_table?.schema_pattern,
                            table: i.source_table?.table_pattern
                          }))
                        }}
                      />
                    </ScrollArea.Autosize>
                  </HoverCard.Dropdown>
                </HoverCard>
              ) : (
                'All'
              )}
            </PropertyCard.Item>

            {task?.source?.binlog_gtid && (
              <PropertyCard.Item label="Start Position">{task.source.binlog_gtid}</PropertyCard.Item>
            )}
            {task?.source?.binlog_name && task?.source?.binlog_position && (
              <PropertyCard.Item label="Start Position">{`${task.source.binlog_name}_${task.source.binlog_position}`}</PropertyCard.Item>
            )}

            {data?.create_time && (
              <PropertyCard.Item label="Creation Time">
                <TimeComponent time={data.create_time} />
              </PropertyCard.Item>
            )}
          </Stack>
        </Card>
      </Stack>

      <Stack justify="flex-start" style={{ flexGrow: 1 }}>
        <Card withBorder shadow="none">
          <Stack>
            <Typography variant="headline-sm">Progress</Typography>
            {data?.state === 'STATE_UNSPECIFIED' ||
              (data?.state === 'CREATING' && (
                <Typography c="carbon.6" variant="body-md">
                  Progress details will appear once the migration task starts running.
                </Typography>
              ))}

            {task && (
              <>
                {showFullMigrateProgress && (
                  <>
                    {task.dump_detail && (
                      <TaskProgress
                        currentStep={task?.current_step}
                        step={PremiumDMSubTaskStep.DUMP}
                        progress={task?.dump_detail.progress}
                        error={task?.error_msg}
                        descriptions={dumpDescriptions}
                      />
                    )}

                    {task.load_detail && (
                      <TaskProgress
                        currentStep={task?.current_step}
                        step={PremiumDMSubTaskStep.LOAD}
                        progress={task?.load_detail.progress}
                        error={task?.error_msg}
                        descriptions={loadDescriptions}
                      />
                    )}
                  </>
                )}

                {showIncrementalProgress && task.sync_detail && (
                  <TaskProgress
                    currentStep={task?.current_step}
                    step={PremiumDMSubTaskStep.SYNC}
                    progress={
                      task?.current_step === PremiumDMSubTaskStep.SYNC
                        ? toNumber(task?.sync_detail?.latency ?? '0') > 0
                          ? 95
                          : 100
                        : 0
                    }
                    error={task?.error_msg}
                    descriptions={syncDescriptions}
                  />
                )}
              </>
            )}
          </Stack>
        </Card>
      </Stack>
    </Group>
  )
}

export default observer(PremiumDmJobDetail)
