import { ActionIcon, Box, Group, Menu, notifier, Typography } from '@tidbcloud/uikit'
import { CollapsibleCard, MRT_ColumnDef, ProTable } 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 { useState } from 'react'
import { useHistory } from 'react-router-dom'

import { humanByteSize } from 'common/services/prommetric'
import { TableFallback } from 'dbaas/components/Table/TableFallback'
import TimeComponent from 'dbaas/components/TimeComponent'
import { useAccessCheck } from 'dbaas/contexts/access-control'
import { tso2date } from 'dbaas/features/Changefeed/tso'
import { getCloudProviderLabel } from 'dbaas/features/Project'
import DeleteModal from 'dbaas/screens/Cluster/Backup/DeleteModal'
import { ServicePlanTag } from 'dbaas/screens/NextGen/shared/tidb-instance/service-plan/ServicePlanTag'
import {
  backupRestoreServiceDeleteRecycledInstanceBackup,
  useBackupRestoreServiceListRecycledInstanceBackups
} from 'dbaas/services/api-clients/legacy/serverless'
import { Backup, RecycledInstance } from 'dbaas/services/api-clients/legacy/serverless/interface'
import {
  useBackupServiceDeleteBackup,
  useBackupServiceListBackups
} from 'dbaas/services/api-clients/v2025/tidb-management/v1beta2'
import {
  Commonv1beta1ServicePlan,
  Nextgenv1beta2Backup,
  V1beta2DeletedTidb
} from 'dbaas/services/api-clients/v2025/tidb-management/v1beta2/interface'
import { deleteBackup as deleteDedicatedBackup, useListBackups } from 'dbaas/services/dataflow'
import { DataflowBackup, DataflowRecycleBinCluster } from 'dbaas/services/dataflow/interface'
import useStores from 'dbaas/stores/useStores'
import { MixpanelEvents } from 'dbaas/utils/tracking'

import { DEFAULT_PAGE_SIZE } from './recycleBinUtils'

// ============================================================
// Unified Backup interface for both Premium/BYOC and Dedicated
// ============================================================
interface NormalizedBackup {
  id: string
  name: string
  backupTime: string | null
  type: string
  size: number
  expirationTime: string | null
  raw: Nextgenv1beta2Backup | DataflowBackup | Backup
}

interface RecycleBinCardConfig {
  clusterId: string
  clusterName: string
  servicePlan: Commonv1beta1ServicePlan | 'Dedicated'
  cloudProvider: string
  region: string
  deleteTime: string
  projectName?: string
  // hooks
  useBackups: (
    pagination: { pageIndex: number; pageSize: number },
    enabled: boolean
  ) => {
    data: NormalizedBackup[]
    total: number
    isLoading: boolean
    refetch: () => void
  }
  deleteBackup: (backup: NormalizedBackup) => Promise<void>
  onRestore: (backup: NormalizedBackup, pageIndex: number) => void
  // access control
  canEdit: boolean
  canRestore: boolean
  // tracking events
  restoreEvent?: string
  deleteEvent?: string
}

function RecycleBinCard({ config }: { config: RecycleBinCardConfig }) {
  const [pagination, setPagination] = useState<{ pageIndex: number; pageSize: number }>({
    pageIndex: 0,
    pageSize: DEFAULT_PAGE_SIZE
  })
  const [opened, setOpened] = useState(false)
  const [deleteBackupModalOpen, deleteBackupModal] = useDisclosure()
  const [selectedBackup, setSelectedBackup] = useState<NormalizedBackup | null>(null)
  const [isDeleting, setIsDeleting] = useState(false)

  const { data, total, isLoading, refetch } = config.useBackups(pagination, opened)

  const handleDeleteBackup = async () => {
    if (!selectedBackup) return
    setIsDeleting(true)
    try {
      await config.deleteBackup(selectedBackup)
      notifier.success(`Backup ${selectedBackup.name} deleted successfully.`)
      deleteBackupModal.close()
      refetch()
    } finally {
      setIsDeleting(false)
    }
  }

  const columns: MRT_ColumnDef<NormalizedBackup>[] = [
    {
      header: 'Backup Name',
      Header: () => <Typography pl={16}>Backup Name</Typography>,
      accessorFn: (row) => <Typography pl={16}>{row.name}</Typography>
    },
    {
      header: 'Backup Time',
      accessorFn: (row) => (row.backupTime ? <TimeComponent time={row.backupTime} /> : '-')
    },
    {
      header: 'Type',
      maxSize: 80,
      accessorFn: (row) => capitalize(row.type)
    },
    ...(config.servicePlan === 'Essential'
      ? []
      : [
          {
            header: 'Size',
            maxSize: 120,
            accessorFn: (row) => humanByteSize(row.size)
          }
        ]),
    {
      header: 'Expires In',
      maxSize: 100,
      accessorFn: (row) => {
        if (row.type === 'MANUAL') return 'Permanent'
        if (!row.expirationTime) return '-'
        const ms = new Date(row.expirationTime).valueOf() - Date.now()
        if (ms <= 0) return 'Expired'
        return (
          <Box title={`Expires at ${new Date(row.expirationTime).toString()}`}>
            {prettyMilliseconds(ms, { compact: true, verbose: true })}
          </Box>
        )
      }
    },
    {
      header: 'Actions',
      Header: () => null,
      id: 'action',
      maxSize: 80,
      accessorFn: (rowData) => (
        <Menu position="bottom-end">
          <Menu.Target>
            <ActionIcon variant="subtle">
              <IconDotsHorizontal size={16} />
            </ActionIcon>
          </Menu.Target>
          <Menu.Dropdown miw={120}>
            <Menu.Item
              disabled={!config.canRestore}
              data-mp-event={config.restoreEvent}
              onClick={() => config.onRestore(rowData, pagination.pageIndex)}
            >
              Restore
            </Menu.Item>
            <Menu.Item
              disabled={!config.canEdit}
              data-mp-event={config.deleteEvent}
              onClick={() => {
                setSelectedBackup(rowData)
                deleteBackupModal.open()
              }}
            >
              Delete
            </Menu.Item>
          </Menu.Dropdown>
        </Menu>
      )
    }
  ]

  return (
    <>
      <CollapsibleCard
        title={
          <Group wrap="nowrap" sx={{ flexGrow: 1 }}>
            <ServicePlanTag servicePlan={config.servicePlan} />
            <Typography fw={500}>{config.clusterName}</Typography>
            <Typography c="carbon.7">
              {getCloudProviderLabel(config.cloudProvider)} ({config.region})
            </Typography>
            <Typography c="carbon.7">
              Deleted at <TimeComponent time={config.deleteTime} />
            </Typography>
            {config.projectName && (
              <Box
                ml="auto"
                bg="carbon.3"
                sx={{ borderRadius: 8, border: '1px solid var(--mantine-color-carbon-4)' }}
                fw={500}
                px={8}
                py={2}
              >
                {config.projectName}
              </Box>
            )}
          </Group>
        }
        onToggle={setOpened}
        contentProps={{ p: 0 }}
      >
        <ProTable
          columns={columns}
          data={data}
          loading={isLoading}
          renderEmptyRowsFallback={() => (
            <TableFallback height="calc(100vh - 300px)">
              <TableFallback.Empty title="No deleted Backups" desc="Deleted Backups will appear here." />
            </TableFallback>
          )}
          manualPagination
          enablePagination
          state={{ pagination }}
          rowCount={total}
          onPaginationChange={setPagination}
          withBorder={false}
          pagination={{
            showRowsPerPage: false,
            showTotal: true,
            wrapperProps: {
              px: 16,
              py: 8,
              sx: { borderTop: '1px solid var(--mantine-color-carbon-3)' }
            }
          }}
        />
      </CollapsibleCard>

      {selectedBackup && (
        <DeleteModal
          isOpen={deleteBackupModalOpen}
          isDeleting={isDeleting}
          id={selectedBackup.id}
          name={selectedBackup.name}
          onClose={() => deleteBackupModal.close()}
          onConfirm={handleDeleteBackup}
        />
      )}
    </>
  )
}

// ============================================================
// Wrapper components to build config for each plan type
// ============================================================
export function RecycleBinPremiumCard({ tidb }: { tidb: V1beta2DeletedTidb }) {
  const history = useHistory()
  const deleteBackupMutation = useBackupServiceDeleteBackup()
  const canEdit = useAccessCheck('TidbxRecycleBinBackupAction')
  const canRestore = useAccessCheck('TidbxBackupRestoreAction')
  const {
    store: {
      lastVisitLocation: { orgId }
    }
  } = useStores()

  const config: RecycleBinCardConfig = {
    clusterId: tidb.tidbId!,
    clusterName: tidb.displayName!,
    servicePlan: tidb.servicePlan!,
    cloudProvider: tidb.cloudProvider!,
    region: tidb.regionId!,
    deleteTime: tidb.deleteTime!,
    canEdit,
    canRestore,
    restoreEvent: MixpanelEvents.RecycleBinPremium.Restore.ButtonClicked,
    deleteEvent: MixpanelEvents.RecycleBinPremium.Delete.ButtonClicked,
    useBackups: (pagination, enabled) => {
      const { data, isLoading, refetch } = useBackupServiceListBackups(
        {
          orgId,
          projectId: '',
          tidbIds: [tidb.tidbId!],
          pageSize: pagination.pageSize,
          skip: pagination.pageIndex * pagination.pageSize
        },
        { query: { refetchOnWindowFocus: false, enabled } }
      )
      return {
        data: (data?.backups ?? []).map((b) => ({
          id: b.id!,
          name: b.displayName!,
          backupTime: tso2date(b.backupTs!)?.toISOString() ?? null,
          type: b.triggerType!,
          size: Number(b.sizeBytes),
          expirationTime: b.expirationTime ?? null,
          raw: b
        })),
        total: data?.totalSize ?? 0,
        isLoading,
        refetch
      }
    },
    deleteBackup: async (backup) => {
      await deleteBackupMutation.mutateAsync({
        backupId: backup.id,
        params: { orgId, projectId: '' }
      })
    },
    onRestore: (backup) => {
      history.push(`/tidbs/recycle-bin/${tidb.tidbId}/restore?plan=${tidb.servicePlan}`, {
        backup: backup.raw,
        tidb
      })
    }
  }

  return <RecycleBinCard config={config} />
}

export function RecycleBinDedicatedCard({ cluster }: { cluster: DataflowRecycleBinCluster }) {
  const history = useHistory()
  const {
    store: { tenantData, userProfile }
  } = useStores()
  const projectName = userProfile.projects.find((p) => p.id === cluster.project_id)?.name
  const canEdit = useAccessCheck('ClusterBackupAction', { projectId: cluster.project_id })
  const canRestore = useAccessCheck('ClusterRestoreAction', { projectId: cluster.project_id })

  const config: RecycleBinCardConfig = {
    clusterId: cluster.id,
    clusterName: cluster.name,
    servicePlan: 'Dedicated',
    cloudProvider: cluster.provider,
    region: cluster.region_name,
    deleteTime: cluster.delete_time,
    projectName,
    canEdit,
    canRestore,
    useBackups: (pagination, enabled) => {
      const { data, isLoading, refetch } = useListBackups(
        tenantData.id,
        cluster.project_id!,
        cluster.id,
        { page: pagination.pageIndex + 1, per_page: pagination.pageSize },
        { query: { refetchOnWindowFocus: false, enabled } }
      )
      return {
        data: (data?.items ?? []).map((b) => ({
          id: b.id,
          name: b.name,
          backupTime: b.backup_ts ?? null,
          type: b.type,
          size: parseInt(b.size ?? '0'),
          expirationTime: b.expiration_time ?? null,
          raw: b
        })),
        total: data?.total ?? 0,
        isLoading,
        refetch
      }
    },
    deleteBackup: async (backup) => {
      await deleteDedicatedBackup(tenantData.id, cluster.project_id!, cluster.id, backup.id)
    },
    onRestore: (backup, pageIndex) => {
      history.push(
        `/tidbs/recycle-bin/${cluster.id}/restore?plan=Dedicated&backupId=${backup.id}&backupProjectId=${cluster.project_id}&backupPage=${pageIndex + 1}`
      )
    }
  }

  return <RecycleBinCard config={config} />
}

export function RecycleBinEssentialCard({ cluster }: { cluster: RecycledInstance }) {
  const history = useHistory()
  const canEdit = useAccessCheck('TidbxRecycleBinBackupAction')
  const canRestore = useAccessCheck('TidbxBackupRestoreAction')
  const {
    store: {
      lastVisitLocation: { orgId }
    }
  } = useStores()

  const config: RecycleBinCardConfig = {
    clusterId: cluster.cluster_id ?? '',
    clusterName: cluster.display_name ?? '',
    servicePlan: 'Essential',
    cloudProvider: cluster.provider ?? '',
    region: cluster.region ?? '',
    deleteTime: cluster.delete_time ?? '',
    canEdit,
    canRestore,
    useBackups: (pagination, enabled) => {
      const { data, isLoading, refetch } = useBackupRestoreServiceListRecycledInstanceBackups(
        orgId,
        cluster.cluster_id ?? '',
        { page_size: pagination.pageSize, page_token: (pagination.pageIndex + 1).toString() },
        {
          query: {
            refetchOnWindowFocus: false,
            enabled
          }
        }
      )

      return {
        data: (data?.backups ?? []).map((b) => ({
          id: b.backup_id ?? '',
          name: b.name ?? '',
          backupTime: b.backup_time ?? null,
          type: b.type ?? '',
          // Essential API does not return size, set to 0 and hide in UI
          size: 0,
          expirationTime: b.expire_time ?? null,
          raw: b
        })),
        total: data?.total_size ?? 0,
        isLoading,
        refetch
      }
    },
    deleteBackup: async (backup) => {
      await backupRestoreServiceDeleteRecycledInstanceBackup(orgId, cluster.cluster_id ?? '', backup.id)
    },
    onRestore: (backup, pageIndex) => {
      history.push(
        `/tidbs/recycle-bin/${cluster.cluster_id ?? ''}/restore?plan=Essential&backup_id=${backup.id}&backup_project_id=${cluster.project_id}&backup_page=${pageIndex + 1}`
      )
    }
  }

  return <RecycleBinCard config={config} />
}
