import {
  ActionIcon,
  Box,
  closeAllModals,
  Group,
  Menu,
  notifier,
  openModal,
  Text,
  Tooltip,
  Typography
} from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import { IconDotsHorizontal } from '@tidbcloud/uikit/icons'
import { useMemoizedFn } from 'ahooks'
import ms from 'ms'
import { useState } from 'react'
import { Link, useHistory } from 'react-router-dom'

import { humanByteSize } from 'common/services/prommetric'
import buildConfig from 'config'
import { HeroComponent } from 'dbaas/components/Measurement'
import { AccessCheck } from 'dbaas/contexts/access-control'
import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import {
  canDeleteDmJob,
  canPauseDmJob,
  canPauseOrScaleWithImportMode,
  canRestartDmJob,
  canResumeDmJob,
  canScaleDmJob
} from 'dbaas/features/DataMigration'
import { DmJobStatus } from 'dbaas/features/DataMigration/JobStatus'
import { isClusterInvalid } from 'dbaas/screens/ClusterV2/components/PausedStatus'
import { getStage } from 'dbaas/screens/DataMigration/utils'
import { Commonv1beta1ClusterState } from 'dbaas/services/api-clients/v2023/cluster-management/v1beta1/interface'
import { useListDMJobs as useDedicatedListDMJobs, useOperateDMJob } from 'dbaas/services/dataflow'
import { SubTaskStep as DedicatedSubTaskStep, DmJob } from 'dbaas/services/dataflow/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'

import { DeleteDMJob } from './DeleteDMJob'
import { renderDMListFallback } from './DMListFallback'
import { DMJobScale } from './DMScale'

const useDedicatedMigrationJobs = (cluster: SharedCluster) => {
  const {
    store: { tenantData, activeProjectId }
  } = useStores()
  const [pagination, setPagination] = useState<{
    pageIndex: number
    pageSize: number
  }>({
    pageIndex: 0,
    pageSize: 10
  })

  const {
    data: dmJobData,
    isLoading,
    refetch,
    isFetched
  } = useDedicatedListDMJobs(
    tenantData.id,
    activeProjectId,
    cluster.id,
    {
      page: pagination.pageIndex,
      page_size: pagination.pageSize
    },
    {
      query: {
        enabled: !isClusterInvalid(cluster),
        refetchInterval: 5000
      },
      request: { timeout: 60_000 }
    }
  )

  const history = useHistory()
  const operateJobMutation = useOperateDMJob()

  const viewJob = useMemoizedFn((id) => {
    history.push(`/clusters/${cluster.id}/data-migration/${id}`)
  })
  const operateJob = useMemoizedFn(async (id: string, op: 'Pause' | 'Resume') => {
    try {
      await operateJobMutation.mutateAsync({
        orgId: tenantData.id,
        projectId: activeProjectId,
        clusterId: cluster.id,
        id,
        data: {
          op
        }
      })
      refetch()
    } catch (e) {
      notifier.error(getErrorMessage(e))
    }
  })

  const columns: MRT_ColumnDef<DmJob>[] = [
    {
      header: 'ID',
      size: 100,
      Header: () => <Typography pl={16}>ID</Typography>,
      accessorFn: (row) => (
        <Typography variant="label-lg" c="carbon.6" pl={16}>
          {row.id}
        </Typography>
      )
    },
    {
      header: 'Job Name',
      accessorFn: (rowData) => {
        return <Link to={`/clusters/${cluster.id}/data-migration/${rowData.id}`}>{rowData.name}</Link>
      }
    },
    {
      header: 'Source',
      size: 80,
      accessorFn: (rowData) => {
        return Object.values(rowData.sub_tasks ?? {})[0]?.source?.conn_profile?.type ?? '-'
      }
    },
    {
      header: 'Stage',
      accessorFn: (rowData) => {
        return getStage(Object.values(rowData.sub_tasks ?? {})[0]?.current_step)
      }
    },
    {
      header: 'Performance',
      accessorFn: (rowData) => {
        const task = Object.values(rowData.sub_tasks ?? {})[0]
        if (task?.current_step === DedicatedSubTaskStep.Dump) {
          return `${humanByteSize(Number(task.dump_detail?.bps ?? 0), false)}/s`
        } else if (task?.current_step === DedicatedSubTaskStep.Load) {
          return `${humanByteSize(Number(task.load_detail?.bps ?? 0), false)}/s`
        } else if (task?.current_step === DedicatedSubTaskStep.Sync) {
          return `${task.sync_detail?.rps ?? 0} Rows/s`
        } else {
          return '-'
        }
      }
    },
    {
      header: 'Latency',
      size: 120,
      accessorFn: (rowData) => {
        const task = Object.values(rowData.sub_tasks ?? {})[0]
        if (task?.current_step === DedicatedSubTaskStep.Sync) {
          return `${ms(Number(task.sync_detail?.latency ?? 0) * 1000)}`
        } else {
          return '-'
        }
      }
    },
    {
      header: 'Status',
      size: 120,
      accessorFn: (rowData) => {
        const task = Object.values(rowData.sub_tasks ?? {})[0]
        const status = task?.stage
        return (
          <Group wrap="nowrap">
            <DmJobStatus status={status!} error={task?.process_error?.message} />
          </Group>
        )
      }
    },
    {
      header: 'Action',
      id: 'action',
      size: 80,
      accessorFn: (rowData) => {
        const handleScale = () => {
          openModal({
            title: (
              <Text c="carbon.9" fw={700} fz={16}>
                Scale Up/Down
              </Text>
            ),
            centered: true,
            size: 720,
            children: <DMJobScale job={rowData} onCancel={closeAllModals} onConfirm={closeAllModals} />
          })
        }
        const handleDelete = () => {
          openModal({
            title: (
              <Text c="carbon.9" fw={700} fz={16}>
                Delete Job
              </Text>
            ),
            centered: true,
            size: 630,
            children: (
              <DeleteDMJob
                job={rowData}
                onCancel={closeAllModals}
                onConfirm={() => {
                  closeAllModals()
                  refetch()
                }}
              />
            )
          })
        }
        const [canPause, disablePauseTip] = canPauseOrScaleWithImportMode(rowData, 'pause')
        const [canScale, disableScaleTip] = canPauseOrScaleWithImportMode(rowData, 'scale')

        return (
          <Menu shadow="md" width={200}>
            <Menu.Target>
              <ActionIcon variant="subtle" size={32}>
                <Box c="carbon.8" component={IconDotsHorizontal} size={18} />
              </ActionIcon>
            </Menu.Target>

            <Menu.Dropdown>
              <Menu.Item onClick={() => viewJob(rowData.id)} data-mp-event="View DM Job detail Clicked">
                View
              </Menu.Item>

              <AccessCheck id="ClusterDMAction">
                {({ accessible }) => (
                  <>
                    {buildConfig.featureFlags.enableDmScale && (
                      <Tooltip label={disableScaleTip} position="left" withArrow disabled={canScale || !accessible}>
                        <div>
                          <Menu.Item
                            disabled={
                              !accessible ||
                              !canScaleDmJob(rowData) ||
                              cluster.state === Commonv1beta1ClusterState.MAINTENANCE
                            }
                            data-mp-event="Open DM Job Scale Up/Down Dialog Clicked"
                            onClick={handleScale}
                          >
                            Scale Up/Down
                          </Menu.Item>
                        </div>
                      </Tooltip>
                    )}

                    <Tooltip label={disablePauseTip} position="left" withArrow disabled={canPause || !accessible}>
                      <div>
                        <Menu.Item
                          disabled={!accessible || !canPauseDmJob(rowData)}
                          onClick={() => operateJob(rowData.id!, 'Pause')}
                          data-mp-event="Pause DM Job Clicked"
                        >
                          Pause
                        </Menu.Item>
                      </div>
                    </Tooltip>

                    {canResumeDmJob(rowData) && (
                      <Menu.Item
                        disabled={!accessible}
                        onClick={() => operateJob(rowData.id!, 'Resume')}
                        data-mp-event="Resume DM Job Clicked"
                      >
                        Resume
                      </Menu.Item>
                    )}

                    {canRestartDmJob(rowData) && (
                      <Menu.Item
                        disabled={!accessible}
                        onClick={() => operateJob(rowData.id!, 'Resume')}
                        data-mp-event="Restart DM Job Clicked"
                      >
                        Resume
                      </Menu.Item>
                    )}

                    {canDeleteDmJob(rowData) && (
                      <Menu.Item
                        disabled={!accessible}
                        onClick={() => {
                          handleDelete()
                        }}
                        data-mp-event="Delete DM Job Clicked"
                      >
                        Delete
                      </Menu.Item>
                    )}
                  </>
                )}
              </AccessCheck>
            </Menu.Dropdown>
          </Menu>
        )
      }
    }
  ]

  return {
    isFetched,
    columns,
    data: dmJobData?.jobs ?? [],
    isLoading,
    total: dmJobData?.total ? Number(dmJobData.total) : 0,
    pagination,
    setPagination
  }
}

export const DedicatedDataMigarationList = ({ cluster }: { cluster: SharedCluster }) => {
  const { isFetched, columns, data, isLoading, total, pagination, setPagination } = useDedicatedMigrationJobs(cluster)
  return (
    <Box>
      {isFetched && <HeroComponent />}

      <ProTable
        columns={columns}
        emptyMessage="No Data Migration Job"
        data={data}
        loading={isLoading}
        enableColumnPinning
        initialState={{ columnPinning: { right: ['action'] } }}
        manualPagination={true}
        state={{ pagination }}
        onPaginationChange={setPagination}
        rowCount={total || 0}
        pagination={{
          showRowsPerPage: true,
          showTotal: true
        }}
        mantinePaperProps={{ mx: 24 }}
        renderEmptyRowsFallback={() => renderDMListFallback(cluster)}
        mantineTableProps={{
          highlightOnHover: false
        }}
      />
    </Box>
  )
}
