import { ActionIcon, Box, Button, Drawer, Group, HoverCard, Menu, Modal, Typography } from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import { useDisclosure } from '@tidbcloud/uikit/hooks'
import { IconDotsHorizontal } from '@tidbcloud/uikit/icons'
import { useTimeout } from 'ahooks'
import { capitalize, omit } from 'lodash-es'
import { observer } from 'mobx-react'
import { useState } from 'react'
import { useHistory } from 'react-router-dom'

import { humanByteSize } from 'common/services/prommetric'
import { HeroComponent } from 'dbaas/components/Measurement'
import TimeComponent from 'dbaas/components/TimeComponent'
import { AccessCheck, AccessDeniedHoverHint, useAccessCheck } from 'dbaas/contexts/access-control'
import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import { DataPlatformFeatureFlag } from 'dbaas/features/Common'
import { useNextGenMode } from 'dbaas/features/Organization/mode'
import { CloudProviderConst } from 'dbaas/features/Project'
import { isClusterInvalid, TableFallback } from 'dbaas/screens/ClusterV2/components/PausedStatus'
import { useDeleteBackup, useGetEnabledDPFeaturesForCluster, useListBackups } from 'dbaas/services/dataflow'
import { BackupExternalStatus, DataflowBackup } from 'dbaas/services/dataflow/interface'
import useStores from 'dbaas/stores/useStores'
import { DEFAULT_TIME_FORMAT_WITH_TIMEZONE } from 'dbaas/utils/format'

import BackupSettingForm from './BackupSettingForm'
import { BackupSettingServerless } from './BackupSettingServerless'
import { BackupSettingV3 } from './BackupSettingV3'
import { BackupStatus } from './BackupStatus'
import DeleteModal from './DeleteModal'
import { ExportedBackupList } from './ExportedBackupList'
import ManualSettingModal from './ManualSettingModal'
import { RestoreHistoryForDedicated } from './RestoreHistoryForDedicated'

interface IBackupOpProps {
  cluster: SharedCluster
}

export function ServerlessBackupListHeader({ cluster }: { cluster: SharedCluster }) {
  const [settingModalOpened, settingModalHandlers] = useDisclosure(false)
  const history = useHistory()
  const { isNextGen } = useNextGenMode()
  const basePath = isNextGen ? '/tidbs' : '/clusters'

  return (
    <Group gap={8}>
      <AccessDeniedHoverHint id="TidbxRestoreCreate" scopeProps={{ tidbId: cluster.id }}>
        {({ accessible }) => (
          <Button
            size="sm"
            data-testid="restore"
            disabled={!accessible}
            onClick={() => history.push(`${basePath}/${cluster.id}/backup/restore`)}
          >
            Restore
          </Button>
        )}
      </AccessDeniedHoverHint>
      <AccessDeniedHoverHint id="TidbxBackupAction">
        {({ accessible }) => (
          <Button
            variant="default"
            data-testid="backup-setting"
            size="sm"
            disabled={!accessible}
            onClick={() => settingModalHandlers.toggle()}
          >
            Backup Setting
          </Button>
        )}
      </AccessDeniedHoverHint>

      <Modal
        opened={settingModalOpened}
        onClose={settingModalHandlers.close}
        title="Backup Setting"
        size={720}
        centered
      >
        <BackupSettingServerless closeModal={settingModalHandlers.close} shareCluster={cluster} />
      </Modal>
    </Group>
  )
}

export const DedicatedBackupListHeader = ({ cluster }: { cluster: SharedCluster }) => {
  const {
    store: { tenantData, activeProjectId }
  } = useStores()
  const history = useHistory()
  const isInvalid = isClusterInvalid(cluster)
  const [settingModalOpened, settingModalHandlers] = useDisclosure(false)
  const [manualBackupModalOpened, manualBackupModalHandlers] = useDisclosure(false)
  const [restoreHistoryOpened, restoreHistoryHandlers] = useDisclosure(false)
  const [exportedBackupListOpened, exportedBackupListHandlers] = useDisclosure(false)
  const { data: featuresData } = useGetEnabledDPFeaturesForCluster(tenantData.id, activeProjectId, cluster?.id!, {
    query: {
      refetchOnWindowFocus: false
    }
  })
  const usingSettingV2 = featuresData?.features.includes(DataPlatformFeatureFlag.SupportBackupWithWorkflow)
  const supportBackupExport = featuresData?.features.includes(DataPlatformFeatureFlag.SupportBackupExport)

  useTimeout(() => {
    const tab = new URLSearchParams(window.location.search).get('tab')
    if (tab === 'exported') {
      exportedBackupListHandlers.open()

      const searchParams = new URLSearchParams(window.location.search)
      searchParams.delete('tab')
      history.replace({
        search: searchParams.toString()
      })
    }
  }, 600)

  return (
    <Group gap={8}>
      <AccessDeniedHoverHint id="ClusterRestoreAction">
        {({ accessible }) => (
          <Button
            size="sm"
            disabled={!accessible}
            data-mp-event="Restore Button Clicked"
            onClick={() => history.push(`/clusters/${cluster.id}/backup/restore`)}
          >
            Restore
          </Button>
        )}
      </AccessDeniedHoverHint>

      <AccessDeniedHoverHint id="ClusterBackupAction">
        {({ accessible }) => (
          <HoverCard shadow="md" withArrow disabled={!isInvalid || !accessible}>
            <HoverCard.Target>
              <div>
                <Button
                  size="sm"
                  onClick={settingModalHandlers.open}
                  disabled={isInvalid || !accessible}
                  data-mp-event="Backup Setting Clicked"
                  variant="default"
                >
                  Backup Setting
                </Button>
              </div>
            </HoverCard.Target>
            <HoverCard.Dropdown>
              The function is unavailable in a {cluster.state.toLowerCase()} state.
            </HoverCard.Dropdown>
          </HoverCard>
        )}
      </AccessDeniedHoverHint>

      <Menu>
        <Menu.Target>
          <ActionIcon aria-label="Backup Actions" variant="default" h={32} w={32} data-testid="backup-more">
            <IconDotsHorizontal size={16} />
          </ActionIcon>
        </Menu.Target>
        <Menu.Dropdown>
          <AccessCheck id="ClusterBackupAction">
            {({ accessible }) => (
              <>
                <Menu.Item
                  onClick={manualBackupModalHandlers.open}
                  data-mp-event="Manual Backup Clicked"
                  data-mp-plan="Dedicated"
                  disabled={isInvalid || !accessible}
                >
                  Manual Backup
                </Menu.Item>
                <Menu.Item
                  data-mp-event="Restore History Clicked"
                  data-testid="restore-history"
                  onClick={restoreHistoryHandlers.open}
                  disabled={!accessible}
                >
                  Restore History
                </Menu.Item>
                {supportBackupExport && (
                  <Menu.Item
                    data-mp-event="Exported Backups Button Clicked"
                    data-testid="exported-backups"
                    onClick={() => {
                      exportedBackupListHandlers.toggle()
                    }}
                    disabled={!accessible}
                  >
                    Exported Backups
                  </Menu.Item>
                )}
              </>
            )}
          </AccessCheck>
        </Menu.Dropdown>
      </Menu>

      <Drawer
        opened={restoreHistoryOpened}
        onClose={restoreHistoryHandlers.close}
        title={<Typography variant="title-lg">Restore History</Typography>}
        position="right"
        size={560}
        padding={16}
      >
        <RestoreHistoryForDedicated />
      </Drawer>

      <Modal
        opened={settingModalOpened}
        onClose={settingModalHandlers.close}
        title="Backup Setting"
        size={864}
        centered
      >
        {usingSettingV2 ? (
          <BackupSettingV3 closeModal={settingModalHandlers.close} />
        ) : (
          <BackupSettingForm closeModal={settingModalHandlers.close} />
        )}
      </Modal>

      <Modal
        opened={manualBackupModalOpened}
        centered
        onClose={manualBackupModalHandlers.close}
        title="Manual Backup"
        size={720}
      >
        <ManualSettingModal closeModal={manualBackupModalHandlers.close} />
      </Modal>

      <Drawer
        opened={exportedBackupListOpened}
        onClose={exportedBackupListHandlers.close}
        title={<Typography variant="title-lg">Exported Backups</Typography>}
        position="right"
        size={560}
      >
        <ExportedBackupList />
      </Drawer>
    </Group>
  )
}

const DedicatedBackupList = (props: IBackupOpProps) => {
  const actionEnabled = useAccessCheck('ClusterBackupAction')
  const restoreEnabled = useAccessCheck('ClusterRestoreAction')
  const [backup, setBackup] = useState<DataflowBackup | null>(null)
  const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
  const history = useHistory()
  const {
    store: { tenantData, activeProjectId }
  } = useStores()
  const { cluster } = props
  const [params, setParams] = useState({ page: 1, totalPage: 0 })
  const itemPerPage = 10
  const deleteBackup = useDeleteBackup()
  const { data: featuresData } = useGetEnabledDPFeaturesForCluster(tenantData.id, activeProjectId, cluster?.id!)
  const usingSettingV2 = featuresData?.features.includes(DataPlatformFeatureFlag.SupportBackupWithWorkflow)

  const supportBackupExport =
    featuresData?.features.includes(DataPlatformFeatureFlag.SupportBackupExport) &&
    // Only AWS and GCP support export for now
    (cluster.provider === CloudProviderConst.AWS || cluster.provider === CloudProviderConst.GCP)

  const { data, refetch, isLoading, isFetched } = useListBackups(
    tenantData.id,
    activeProjectId,
    cluster.id,
    {
      page: params.page,
      per_page: itemPerPage
    },
    {
      query: {
        refetchInterval: 5000,
        onSuccess(data) {
          setParams({
            ...params,
            totalPage: Math.ceil((data?.total ?? 0) / itemPerPage)
          })
        }
      }
    }
  )

  const handleDeleteBackup = async (backupId: string) => {
    try {
      await deleteBackup.mutateAsync({
        orgId: tenantData.id,
        projectId: activeProjectId,
        clusterId: cluster.id,
        id: backupId
      })
      setShowDeleteConfirm(false)
      await refetch()
    } catch (e) {
      throw e
    }
  }

  const columns: MRT_ColumnDef<DataflowBackup>[] = [
    {
      header: 'Name',
      Header: <Typography pl={16}>Name</Typography>,
      accessorFn: (row: DataflowBackup) => <Typography pl={16}>{row.name}</Typography>
    },
    {
      header: 'Backup Time',
      Header: () => <Typography pl={16}>Backup Time</Typography>,
      accessorFn: (row: DataflowBackup) => {
        return (
          <Box pl={16}>
            <TimeComponent
              time={row.backup_ts!}
              format={DEFAULT_TIME_FORMAT_WITH_TIMEZONE}
              utcOffset={tenantData.timezone}
            />
          </Box>
        )
      },
      minWidth: 210
    },
    {
      header: 'Type',
      accessorFn: ({ type }: DataflowBackup) => (type ? capitalize(type) : '-'),
      maxSize: 100
    },
    {
      header: 'TSO',
      accessorKey: 'backup_tso',
      maxSize: 200
    },
    {
      header: 'Size',
      accessorFn: ({ size }: DataflowBackup) => humanByteSize(parseInt(size), false),
      maxSize: 80
    },
    {
      header: 'Region',
      accessorFn: ({ regions }: DataflowBackup) => <Typography>{regions?.map((i) => i.name).join(', ')}</Typography>,
      show: usingSettingV2,
      maxSize: 100
    },
    {
      header: 'Status',
      accessorFn: ({ status }: DataflowBackup) => {
        if (!status) return '-'
        return <BackupStatus status={status} />
      },
      maxSize: 100
    },
    {
      header: 'Action',
      size: 60,
      accessorFn: (rowData: DataflowBackup) => {
        return (
          <Menu shadow="md" width={200}>
            <Menu.Target>
              <ActionIcon aria-label={`${rowData.name} actions`} variant="subtle" size={32}>
                <IconDotsHorizontal size={16} />
              </ActionIcon>
            </Menu.Target>
            <Menu.Dropdown>
              <Menu.Item
                onClick={() => {
                  history.push(`/clusters/${cluster.id}/backup/restore?backup_id=${rowData.id}`)
                }}
                data-mp-event="Backup Restore Action Button Clicked"
                disabled={rowData.status !== BackupExternalStatus.SUCCESS || !restoreEnabled}
              >
                Restore
              </Menu.Item>
              {supportBackupExport && (
                <Menu.Item
                  disabled={rowData.status !== BackupExternalStatus.SUCCESS}
                  onClick={() => {
                    history.push(
                      `/clusters/${cluster.id}/backup/export?backup=${btoa(JSON.stringify({ id: rowData.id, name: rowData.name, time: rowData.backup_ts }))}`
                    )
                  }}
                  data-mp-event="Export Backup Action Button Clicked"
                >
                  Export
                </Menu.Item>
              )}
              <Menu.Item
                onClick={() => {
                  setBackup(rowData)
                  setShowDeleteConfirm(true)
                }}
                data-mp-event="Backup Delete Button Clicked"
              >
                Delete
              </Menu.Item>
            </Menu.Dropdown>
          </Menu>
        )
      },
      show: actionEnabled
    }
  ]
    .filter((i) => i.show !== false)
    .map((i) => omit(i, ['show'])) as MRT_ColumnDef<DataflowBackup>[]

  return (
    <div className="backup-panel">
      {isFetched && <HeroComponent />}

      <ProTable
        data-testid="backup-list-table"
        loading={isLoading}
        columns={columns}
        emptyMessage="No Backup"
        data={data?.items ?? []}
        manualPagination={true}
        pagination={
          data?.items?.length
            ? {
                value: params.page,
                total: params.totalPage,
                onChange: (p) => setParams((prev) => ({ ...prev, page: p })),
                position: 'center'
              }
            : undefined
        }
        renderEmptyRowsFallback={() => {
          if (isClusterInvalid(cluster) && !isLoading && !data?.items?.length) {
            return (
              <TableFallback>
                <TableFallback.Paused
                  cluster={cluster}
                  featureName="Backup"
                  featureDesc="Configure a backup schedule for your cluster to periodically back up your data."
                  customTitle={`The cluster is ${cluster.state.toLowerCase()}, and scheduled backups are not being taken`}
                />
              </TableFallback>
            )
          }

          return (
            <TableFallback>
              <TableFallback.Empty
                title="Get started by setting your backup"
                desc="Configure a backup schedule for your cluster to periodically back up your data."
              />
            </TableFallback>
          )
        }}
        mantinePaperProps={{ mx: 24 }}
        mantineTableProps={{
          highlightOnHover: false
        }}
      />

      {backup && (
        <DeleteModal
          isOpen={showDeleteConfirm}
          isDeleting={deleteBackup.isLoading}
          id={backup.id}
          name={backup.name}
          onClose={() => setShowDeleteConfirm(false)}
          onConfirm={handleDeleteBackup}
        />
      )}
    </div>
  )
}

export default observer(DedicatedBackupList)
