import {
  ActionIcon,
  Anchor,
  Button,
  Drawer,
  Group,
  Loader,
  Menu,
  Modal,
  notifier,
  Stack,
  TextInput,
  Typography
} from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable, ProTableProps } from '@tidbcloud/uikit/biz'
import { useDebouncedValue } from '@tidbcloud/uikit/hooks'
import { IconDotsHorizontal, IconRefreshCcw02, IconSearchLg } from '@tidbcloud/uikit/icons'
import { useMemoizedFn, useMount } from 'ahooks'
import { ReactNode, useState } from 'react'
import { useHistory } from 'react-router-dom'

import { HeroComponent, isHeroQueryReady } from 'dbaas/components/Measurement'
import { renderTimeColumn } from 'dbaas/components/Table/utils'
import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import { ExportTargets } from 'dbaas/features/Import'
import { ExportStatus } from 'dbaas/features/Import/ExportStatus'
import { TableFallback } from 'dbaas/screens/ClusterV2/components/PausedStatus'
import {
  useExportServiceCancelExport,
  useExportServiceDeleteExport,
  useExportServiceListExports
} from 'dbaas/services/api-clients/legacy/serverless'
import {
  Export as ServerlessExport,
  ExportStateEnum as ServerlessExportStateEnum
} from 'dbaas/services/api-clients/legacy/serverless/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'

import ExportTaskDetail from '../ImportV3/ExportTaskDetail'

export const ExportList = ({ cluster }: { cluster: SharedCluster }) => {
  const {
    store: { tenantData, activeProjectId }
  } = useStores()
  const history = useHistory()
  const urlParams = new URLSearchParams(window.location.search)
  const [exportId, setExportId] = useState(urlParams.get('exportId') ?? '')
  const [exportSearchQuery, setExportSearchQuery] = useState('')
  const [opened, setOpened] = useState(false)
  const [debouncedExportSearchQuery] = useDebouncedValue(exportSearchQuery, 600)
  const [params, setParams] = useState({
    page: 1,
    pages: 0
  })
  const [confirmModalProps, setConfirmModalProps] = useState({
    open: false,
    title: '',
    content: '' as ReactNode,
    onConfirm: () => {}
  })
  const cancelExport = useExportServiceCancelExport()
  const deleteExport = useExportServiceDeleteExport()

  const {
    data: exportData,
    isFetched,
    isError,
    isLoading: isExportLoading,
    isFetching: isExportFetching,
    refetch: refetchExportList
  } = useExportServiceListExports(
    tenantData.id,
    activeProjectId,
    cluster.id,
    {
      page_size: 10,
      page_token: params.page + '',
      display_name_like: debouncedExportSearchQuery,
      order_by: 'create_time desc'
    },
    {
      query: {
        refetchInterval: 30 * 1000,
        onSuccess(data) {
          setParams({
            ...params,
            pages: Math.ceil(data?.total_size! / 10)
          })
        }
      }
    }
  )
  const closeConfirmModal = () => setConfirmModalProps((prev) => ({ ...prev, open: false }))
  const handleCancelExport = useMemoizedFn((id: string, name: string) => {
    setConfirmModalProps({
      title: 'Cancel export task',
      content: (
        <Typography>
          Export task <b>{name}</b> cannot be continued after cancellation. Confirm to cancel this task?
        </Typography>
      ),
      open: true,
      onConfirm: async () => {
        try {
          await cancelExport.mutateAsync({
            orgId: tenantData.id,
            projectId: activeProjectId,
            clusterId: cluster.id,
            exportId: id,
            data: {
              exportServiceCancelExportBody: {}
            }
          })
          notifier.success('Export task successfully cancelled.')
          closeConfirmModal()
          refetchExportList()
        } catch (e) {
          notifier.error(getErrorMessage(e, true))
        }
      }
    })
  })

  const handleDeleteExportTask = useMemoizedFn((id: string, name: string) => {
    setConfirmModalProps({
      title: 'Delete export task',
      content: (
        <Typography variant="body-lg">
          Export task <b>{name}</b> cannot be recovered after deletion. Continue to delete this task?
        </Typography>
      ),
      open: true,
      onConfirm: async () => {
        try {
          await deleteExport.mutateAsync({
            orgId: tenantData.id,
            projectId: activeProjectId,
            clusterId: cluster.id,
            exportId: id
          })
          notifier.success('Export task successfully deleted.')
          closeConfirmModal()
          refetchExportList()
        } catch (e) {
          notifier.error(getErrorMessage(e))
        }
      }
    })
  })

  const exportDataColumns: MRT_ColumnDef<ServerlessExport>[] = [
    {
      header: 'Name',
      Header: () => <Typography pl={16}>Name</Typography>,
      accessorFn: (data: ServerlessExport) => (
        <Typography
          truncate
          pl={16}
          onClick={() => {
            setExportId(data.export_id!)
            setOpened(true)
          }}
        >
          <Anchor color="peacock">{data.display_name}</Anchor>
        </Typography>
      ),
      id: 'name',
      minSize: 200,
      maxSize: 400
    },
    {
      header: 'Status',
      accessorFn: (data: ServerlessExport) => <ExportStatus status={data.state!} error={data.reason} withinPortal />,
      id: 'state',
      maxSize: 100
    },
    {
      header: 'Creation Time',
      accessorFn: renderTimeColumn('create_time', 'YYYY-MM-DD HH:mm:ss'),
      id: 'created_at',
      size: 150
    },
    {
      header: 'Target',
      size: 120,
      accessorFn: (data: ServerlessExport) => {
        return <Typography>{ExportTargets.find((target) => target.value === data.target?.type)?.label}</Typography>
      }
    },
    {
      header: 'Source',
      maxSize: 300,
      accessorFn: (data: ServerlessExport) => {
        if (data?.export_options?.filter?.table?.patterns?.length) {
          return data.export_options?.filter?.table?.patterns?.join(', ')
        }
        if (data?.export_options?.filter?.table?.where) {
          return data.export_options?.filter?.table?.where
        }
        if (data?.export_options?.filter?.sql) {
          return (
            <Typography truncate maw={300} title={data?.export_options?.filter?.sql}>
              {data?.export_options?.filter?.sql}
            </Typography>
          )
        }
        return '-'
      }
    },
    {
      header: 'Action',
      size: 50,
      accessorFn: (data: ServerlessExport) => {
        return (
          <Menu shadow="md" position="bottom">
            <Menu.Target>
              <ActionIcon aria-label={`${data.display_name} actions`} variant="subtle">
                <IconDotsHorizontal size={16} />
              </ActionIcon>
            </Menu.Target>

            <Menu.Dropdown>
              <Menu.Item
                onClick={() => {
                  setExportId(data.export_id!)
                  setOpened(true)
                }}
              >
                View
              </Menu.Item>
              {data.state === ServerlessExportStateEnum.RUNNING && (
                <Menu.Item onClick={() => handleCancelExport(data.export_id!, data.display_name!)}>Cancel</Menu.Item>
              )}

              <Menu.Item onClick={() => handleDeleteExportTask(data.export_id!, data.display_name!)}>Delete</Menu.Item>
            </Menu.Dropdown>
          </Menu>
        )
      }
    }
  ]

  const pagination: ProTableProps<any>['pagination'] = {
    total: params.pages,
    value: params.page,
    onChange(page: number) {
      setParams({
        ...params,
        page
      })
    }
  }

  useMount(() => {
    if (exportId && !opened) {
      setTimeout(() => {
        setOpened(true)
        const searchParams = new URLSearchParams(window.location.search)
        searchParams.delete('exportId')
        history.replace({ search: searchParams.toString() }) // remove url search params
      }, 600)
    }
  })

  return (
    <Stack data-testid="export-list">
      <HeroComponent ready={isHeroQueryReady({ isFetched, isError })} />
      <Group px={24} justify="space-between">
        <TextInput
          leftSection={<IconSearchLg size={16} />}
          placeholder="Find specific task"
          value={exportSearchQuery}
          onChange={(e) => setExportSearchQuery(e.target.value)}
          miw={320}
        />

        <ActionIcon
          aria-label="Refresh"
          onClick={() => {
            refetchExportList()
          }}
          variant="subtle"
        >
          {isExportFetching ? <Loader size="xs" /> : <IconRefreshCcw02 size={16} />}
        </ActionIcon>
      </Group>

      <ProTable
        data-testid="export-list-table"
        columns={exportDataColumns}
        emptyMessage="No Data"
        data={exportData?.exports || []}
        loading={isExportLoading}
        mantinePaperProps={{ mx: 24 }}
        manualPagination={true}
        pagination={exportData?.exports?.length ? pagination : undefined}
        renderEmptyRowsFallback={() => {
          if (debouncedExportSearchQuery) {
            return null
          }

          return (
            <TableFallback height="calc(100vh - 370px)">
              <TableFallback.Empty
                title="Get started by exporting your data"
                desc="Export data from your TiDB Cloud cluster using the TiDB Cloud console. This feature allows you to
                        save your data to local files or cloud storage services such as Amazon S3, Google Cloud Storage,
                        Azure Blob Storage and Alibaba Cloud OSS. You have the option to choose from various target formats, including SQL, CSV, or
                        Parquet, and you can also select flexible compression options."
              />
            </TableFallback>
          )
        }}
      />

      <Modal
        title={confirmModalProps.title}
        opened={confirmModalProps.open}
        onClose={() => setConfirmModalProps((prev) => ({ ...prev, open: false }))}
        centered
      >
        <Stack>
          {confirmModalProps.content}

          <Group justify="flex-end">
            <Button variant="default" onClick={() => setConfirmModalProps((prev) => ({ ...prev, open: false }))}>
              No
            </Button>
            <Button
              color="red"
              variant="light"
              onClick={() => {
                confirmModalProps.onConfirm()
              }}
              loading={cancelExport.isLoading || deleteExport.isLoading}
            >
              Yes, I confirm
            </Button>
          </Group>
        </Stack>
      </Modal>

      <Drawer
        size={540}
        position="right"
        opened={opened}
        overlayProps={{ opacity: 0.5 }}
        zIndex={1000}
        styles={() => ({
          root: {
            '--drawer-height': '100vh'
          },
          content: {
            display: 'flex',
            flexDirection: 'column'
          },
          body: {
            flexGrow: 1
          }
        })}
        title={
          <Typography px={8} variant="headline-md">
            Export Task Detail
          </Typography>
        }
        onClose={() => {
          setOpened(false)
          setExportId('')
        }}
      >
        <ExportTaskDetail id={exportId} key={exportId} />
      </Drawer>
    </Stack>
  )
}
