import useUrlState from '@ahooksjs/use-url-state'
import {
  ActionIcon,
  Box,
  Button,
  Center,
  Group,
  Menu,
  Modal,
  notifier,
  Select,
  Stack,
  Typography
} from '@tidbcloud/uikit'
import {
  MRT_ColumnDef,
  ProTable,
  TimeRangePicker,
  toTimeRangeValue,
  toURLTimeRange,
  urlToTimeRange
} from '@tidbcloud/uikit/biz'
import { useDisclosure } from '@tidbcloud/uikit/hooks'
import { IconDotsHorizontal } from '@tidbcloud/uikit/icons'
import { capitalize } from 'lodash-es'
import prettyMilliseconds from 'pretty-ms'
import { useMemo, useState } from 'react'
import { useHistory } from 'react-router-dom'

import { humanByteSize } from 'common/services/prommetric'
import { HeroComponent, isHeroQueryReady } from 'dbaas/components/Measurement'
import TimeComponent from 'dbaas/components/TimeComponent'
import { AccessDeniedHoverHint, AccessGuard, useAccessCheck } from 'dbaas/contexts/access-control'
import { tso2date } from 'dbaas/features/Changefeed/tso'
import { useOrgProjectClusterIds } from 'dbaas/features/Common'
import { BackupStatusPremium } from 'dbaas/screens/Cluster/Backup/BackupStatus'
import DeleteModal from 'dbaas/screens/Cluster/Backup/DeleteModal'
import { isClusterInvalid, TableFallback } from 'dbaas/screens/ClusterV2/components/PausedStatus'
import { useSharedTiDBContext } from 'dbaas/screens/NextGen/tidb-mgmt-container/shared/tidb-context'
import { TiDBPageShell } from 'dbaas/screens/NextGen/tidb-mgmt-container/shared/TiDBPageShell'
import {
  useTidbServiceDeleteTidbBackup,
  useTidbServiceListTidbBackups
} from 'dbaas/services/api-clients/v2025/tidb-management/v1beta2'
import {
  Nextgenv1beta2Backup,
  Nextgenv1beta2BackupTriggerType
} from 'dbaas/services/api-clients/v2025/tidb-management/v1beta2/interface'
import { MixpanelEvents } from 'dbaas/utils/tracking'

import { usePremiumManualBackupFeatDisabled } from './flag'
import { BackupSettingLegacy } from './LegacySettings'
import { ManualBackupPremium } from './Manual'
import { BackupSettingPremium } from './Settings'
import { BackupSettingSummary } from './SettingsSummary'

const BackupListPremium = () => {
  const tidb = useSharedTiDBContext()
  const [settingModalOpened, settingModal] = useDisclosure()
  const [manualBackupOpened, manualBackupModal] = useDisclosure()
  const [deleteBackupModalOpen, deleteBackupModal] = useDisclosure()
  const [pagination, setPagination] = useState<{
    pageIndex: number
    pageSize: number
  }>({
    pageIndex: 0,
    pageSize: 10
  })
  const { orgId, projectId } = useOrgProjectClusterIds()
  const [filters, setFilters] = useUrlState<{
    type?: string
    from?: string
    to?: string
  }>(
    {
      type: undefined,
      from: undefined,
      to: undefined
    },
    { navigateMode: 'replace' }
  )
  const hasSearch = filters.type || filters.from || filters.to
  const timeRange = useMemo(() => {
    return filters.from && filters.to ? urlToTimeRange({ from: filters.from, to: filters.to }) : undefined
  }, [filters.from, filters.to])
  const timeRangeValue = timeRange ? toTimeRangeValue(timeRange) : undefined
  const { data, isLoading, isFetched, isError, refetch } = useTidbServiceListTidbBackups(
    tidb.tidbId!,
    {
      orgId,
      projectId,
      triggerTypes: filters.type ? [filters.type] : undefined,
      startTime: timeRangeValue?.[0] ? new Date(timeRangeValue[0] * 1000).toISOString() : undefined,
      endTime: timeRangeValue?.[1] ? new Date(timeRangeValue[1] * 1000).toISOString() : undefined,

      pageSize: pagination.pageSize,
      skip: pagination.pageIndex * pagination.pageSize
    },
    {
      query: {
        refetchOnWindowFocus: !hasSearch,
        refetchInterval: (data) => {
          if (hasSearch) return false

          const hasPendingBackups = data?.backups?.some((backup) => backup.state !== 'SUCCEEDED')

          return hasPendingBackups ? 5000 : 30000
        }
      }
    }
  )
  const history = useHistory()
  const isPremiumManualBackupDisabled = usePremiumManualBackupFeatDisabled()
  const isPremiumFamily = tidb.computed.isPremium || tidb.computed.isBYOC || tidb.computed.isPremiumReserved
  const isEssentialV2 = tidb.computed.isEssentialV2
  const hasEditableBackupSettings = isPremiumFamily || isEssentialV2
  const canCreateManualBackup = isPremiumFamily && !isPremiumManualBackupDisabled
  const handleRestore = () => {
    history.push(`/tidbs/${tidb.tidbId}/restore`)
  }
  const deleteBackup = useTidbServiceDeleteTidbBackup()
  const [selectedBackup, setSelectedBackup] = useState<Nextgenv1beta2Backup | null>(null)
  const handleDeleteBackup = async () => {
    if (selectedBackup) {
      await deleteBackup.mutateAsync({
        tidbId: selectedBackup.tidbId!,
        backupId: selectedBackup.id!,
        params: {
          orgId,
          projectId
        }
      })
      notifier.success(`Backup ${selectedBackup.displayName} deleted successfully.`)
      deleteBackupModal.close()
      refetch()
    }
  }
  const backupAccessible = useAccessCheck('TidbxBackupAction')
  const restoreAccessible = useAccessCheck('TidbxRestoreCreate', { tidbId: tidb.tidbId })
  const columns: MRT_ColumnDef<Nextgenv1beta2Backup>[] = [
    {
      header: 'Backup Name',
      Header: () => {
        return <Typography pl={16}>Backup Name</Typography>
      },
      accessorFn: (row) => {
        return <Box pl={16}>{row.displayName}</Box>
      }
    },
    {
      header: 'Backup Time',
      accessorFn: (row) => {
        if (row.backupTs === '0') return '-'

        const date = tso2date(row.backupTs!)
        if (date) {
          return <TimeComponent time={date} />
        }
        return '-'
      }
    },
    {
      header: 'Type',
      maxSize: 80,
      accessorFn: (row) => {
        return capitalize(row.triggerType)
      }
    },
    {
      header: 'TSO',
      accessorFn: (row) => {
        return row.backupTs
      }
    },
    {
      header: tidb.computed.isEssentialV2 ? 'File Size (Estimated)' : 'File Size',
      maxSize: 120,
      accessorFn: (row) => {
        if (row.sizeBytes && Number(row.sizeBytes) > 0) {
          return humanByteSize(Number(row.sizeBytes))
        }
        return row.state === 'SUCCEEDED' ? humanByteSize(Number(row.sizeBytes)) : 'Calculating'
      }
    },
    {
      header: 'Status',
      maxSize: 120,
      accessorFn: (row) => {
        return <BackupStatusPremium status={row.state!} />
      }
    },
    {
      header: 'Expires In',
      maxSize: 120,
      accessorFn: (row) => {
        if (row.triggerType === Nextgenv1beta2BackupTriggerType.MANUAL) {
          return 'Permanent'
        }
        if (row.expirationTime) {
          const expireDate = new Date(row.expirationTime)
          const ms = expireDate.valueOf() - new Date().valueOf()
          return (
            <Box title={`Expires at ${expireDate.toString()}`}>
              {ms <= 0
                ? 'Expired'
                : prettyMilliseconds(ms, {
                    compact: true,
                    verbose: true
                  })}
            </Box>
          )
        }

        return '-'
      }
    },
    {
      header: 'Actions',
      Header: () => null,
      id: 'action',
      maxSize: 80,
      accessorFn: (rowData) => {
        return (
          <Menu position="bottom-end">
            <Menu.Target>
              <ActionIcon variant="subtle">
                <IconDotsHorizontal size={16} />
              </ActionIcon>
            </Menu.Target>
            <Menu.Dropdown miw={120}>
              <Menu.Item
                disabled={!restoreAccessible}
                data-mp-event={MixpanelEvents.PremiumBackup.Restore.ButtonClicked}
                onClick={() => {
                  history.push(`/tidbs/${tidb.tidbId}/restore`, {
                    backup: rowData
                  })
                }}
              >
                Restore
              </Menu.Item>
              <Menu.Item
                disabled={!backupAccessible}
                data-mp-event={MixpanelEvents.PremiumBackup.Delete.ButtonClicked}
                onClick={() => {
                  deleteBackup.reset()
                  setSelectedBackup(rowData)
                  deleteBackupModal.open()
                }}
              >
                Delete
              </Menu.Item>
            </Menu.Dropdown>
          </Menu>
        )
      }
    }
  ]

  return (
    <TiDBPageShell
      title="Backups"
      headerProps={{
        withBack: false,
        rightSection: (
          <Group gap={8}>
            <AccessDeniedHoverHint id="TidbxRestoreCreate" scopeProps={{ tidbId: tidb.tidbId }}>
              {({ accessible }) => (
                <Button
                  size="sm"
                  data-testid="premium-backup-restore"
                  data-mp-event={MixpanelEvents.PremiumBackup.Restore.ButtonClicked}
                  onClick={handleRestore}
                  disabled={!accessible || isClusterInvalid(tidb)}
                >
                  Restore
                </Button>
              )}
            </AccessDeniedHoverHint>

            {isPremiumFamily ? (
              <>
                {canCreateManualBackup && (
                  <AccessDeniedHoverHint id="TidbxBackupAction">
                    <Button
                      size="sm"
                      variant="default"
                      disabled={!backupAccessible || isClusterInvalid(tidb)}
                      onClick={manualBackupModal.open}
                      data-testid="premium-manual-backup-open"
                      data-mp-event={MixpanelEvents.PremiumBackup.Create.ButtonClicked}
                    >
                      Manual Backup
                    </Button>
                  </AccessDeniedHoverHint>
                )}

                <Menu position="bottom-end">
                  <Menu.Target>
                    <ActionIcon
                      aria-label="Backup Actions"
                      variant="default"
                      h={32}
                      w={32}
                      data-testid="premium-backup-more-actions"
                      data-mp-event={MixpanelEvents.PremiumBackup.View.ButtonClicked}
                    >
                      <IconDotsHorizontal size={16} />
                    </ActionIcon>
                  </Menu.Target>
                  <Menu.Dropdown>
                    <Menu.Item
                      disabled={!backupAccessible || isClusterInvalid(tidb)}
                      onClick={settingModal.open}
                      data-testid="premium-backup-settings-open"
                      data-mp-event={MixpanelEvents.PremiumBackup.Update.ButtonClicked}
                    >
                      Backup Settings
                    </Menu.Item>
                    <Menu.Item
                      onClick={() => history.push(`/tidbs/${tidb.tidbId}/exports`)}
                      data-testid="premium-exported-backups-open"
                      data-mp-event={MixpanelEvents.PremiumExport.View.ButtonClicked}
                    >
                      Exported Backups
                    </Menu.Item>
                  </Menu.Dropdown>
                </Menu>
              </>
            ) : (
              <AccessDeniedHoverHint id="TidbxBackupAction">
                <Button
                  size="sm"
                  variant="default"
                  onClick={settingModal.open}
                  disabled={!backupAccessible || isClusterInvalid(tidb)}
                  data-testid="premium-backup-settings-open"
                  data-mp-event={MixpanelEvents.PremiumBackup.Update.ButtonClicked}
                >
                  Backup Settings
                </Button>
              </AccessDeniedHoverHint>
            )}
          </Group>
        )
      }}
    >
      <HeroComponent ready={isHeroQueryReady({ isFetched, isError })} />
      <Stack>
        <Group justify="space-between" align="center" wrap="nowrap">
          <Group>
            <Select
              placeholder="Type"
              value={filters.type}
              onChange={(value) => {
                setFilters((prev) => ({ ...prev, type: value ?? undefined }))
                setPagination((prev) => ({ ...prev, pageIndex: 0 }))
              }}
              data={[
                { value: Nextgenv1beta2BackupTriggerType.AUTO, label: 'Auto' },
                ...(isPremiumFamily ? [{ value: Nextgenv1beta2BackupTriggerType.MANUAL, label: 'Manual' }] : [])
              ]}
              clearable
            />

            <TimeRangePicker
              value={timeRange}
              onChange={(v) => {
                const { from, to } = v ? toURLTimeRange(v) : { from: undefined, to: undefined }
                setFilters((prev) => ({ ...prev, from, to }))
                setPagination((prev) => ({ ...prev, pageIndex: 0 }))
              }}
              placeholder="Select backup time range"
              clearable
              maxDateTime={() => new Date()}
            />
          </Group>

          {hasEditableBackupSettings && (
            <BackupSettingSummary
              tidbId={tidb.tidbId!}
              servicePlan={tidb.servicePlan!}
              canChangeSettings={backupAccessible && !isClusterInvalid(tidb)}
              onChangeSettings={settingModal.open}
            />
          )}
        </Group>
        <ProTable
          columns={columns}
          data={data?.backups ?? []}
          loading={isLoading}
          manualPagination
          enablePagination
          state={{ pagination }}
          onPaginationChange={setPagination}
          rowCount={data?.totalSize || 0}
          pagination={{
            showRowsPerPage: true,
            showTotal: true
          }}
          renderEmptyRowsFallback={() => {
            if (hasSearch) {
              return (
                <Center py={24}>
                  <Typography variant="body-lg" c="carbon.7">
                    {isError ? 'Error occurred, please try again later.' : 'No backups found.'}
                  </Typography>
                </Center>
              )
            }
            return (
              <TableFallback height="calc(100vh - 280px)">
                <TableFallback.Empty
                  title="Get started by setting your backup"
                  desc="Configure a backup schedule for your instance to periodically back up your data."
                />
              </TableFallback>
            )
          }}
        />

        <AccessGuard id="TidbxBackupAction">
          <Modal
            title="Backup Settings"
            opened={settingModalOpened}
            onClose={settingModal.close}
            size={hasEditableBackupSettings ? 880 : 'lg'}
          >
            {settingModalOpened &&
              (hasEditableBackupSettings ? (
                <BackupSettingPremium
                  tidbId={tidb.tidbId!}
                  instanceName={tidb.displayName}
                  servicePlan={tidb.servicePlan!}
                  isBYOC={tidb.computed.isBYOC}
                  closeModal={settingModal.close}
                />
              ) : (
                <BackupSettingLegacy tidbId={tidb.tidbId!} />
              ))}
          </Modal>

          {canCreateManualBackup ? (
            <Modal title="Manual Backup" opened={manualBackupOpened} onClose={manualBackupModal.close} size="lg">
              <ManualBackupPremium
                closeModal={manualBackupModal.close}
                onSuccess={async () => {
                  await refetch()
                }}
              />
            </Modal>
          ) : null}

          {selectedBackup && (
            <DeleteModal
              isOpen={deleteBackupModalOpen}
              isDeleting={deleteBackup.isLoading}
              id={selectedBackup.id!}
              name={selectedBackup.displayName!}
              onClose={() => deleteBackupModal.close()}
              onConfirm={handleDeleteBackup}
            />
          )}
        </AccessGuard>
      </Stack>
    </TiDBPageShell>
  )
}

export default BackupListPremium
