import { Anchor, Button, Card, Center, Group, Loader, Modal, notifier, Stack, Typography } from '@tidbcloud/uikit'
import { PropertyCard } from '@tidbcloud/uikit/biz'
import { useMemoizedFn } from 'ahooks'
import { observer } from 'mobx-react'
import { useMemo, useState } from 'react'

import TimeComponent from 'dbaas/components/TimeComponent'
import { BackupExportStatus } from 'dbaas/features/BackupRestore/BackupExportStatus'
import { useOrgProjectClusterIds } from 'dbaas/features/Common'
import { useCancelBackupExport, useListBackupExports } from 'dbaas/services/dataflow'
import { DataflowBackupExport, DataflowBackupExportStatus } from 'dbaas/services/dataflow/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'

const ExportedBackupCard = observer(
  ({ data, onCancel }: { data: DataflowBackupExport; onCancel: (data: DataflowBackupExport) => void }) => {
    const {
      store: { tenantData }
    } = useStores()
    const isCancelable = [DataflowBackupExportStatus.PENDING, DataflowBackupExportStatus.RUNNING].includes(
      data.status as any
    )
    return (
      <Card>
        <Group justify="space-between" mb={8}>
          <Typography variant="title-md">{`${data.backup_name ?? data.backup_id}`}</Typography>

          {isCancelable && (
            <Button variant="default" size="xs" onClick={() => onCancel(data)}>
              Cancel
            </Button>
          )}
        </Group>

        <Stack gap={8}>
          <PropertyCard.Item label="Status" labelProps={{ miw: 80 }}>
            <BackupExportStatus withinPortal status={data.status!} error={data.error_msg} />
          </PropertyCard.Item>

          <PropertyCard.Item label="Folder URI" labelProps={{ miw: 80 }} sx={{ alignItems: 'flex-start' }}>
            {data.gcs?.target_uri || data.s3?.target_uri || data.az_blob?.target_uri}
          </PropertyCard.Item>

          <PropertyCard.Item label="Export Time" labelProps={{ miw: 80 }}>
            <TimeComponent time={data.created_at!} utcOffset={tenantData.timezone} />
          </PropertyCard.Item>
        </Stack>
      </Card>
    )
  }
)

export const ExportedBackupList = observer(() => {
  const { orgId, projectId, clusterId } = useOrgProjectClusterIds()
  const PER_PAGE = 10

  const [pagination, setPagination] = useState({
    page: 1,
    size: PER_PAGE
  })
  const [firstLoadDone, setFirstLoadDone] = useState(false)
  const { data, isLoading, isFetching, refetch, isFetched } = useListBackupExports(
    orgId,
    projectId,
    clusterId!,
    {
      page: 1,
      per_page: pagination.size
    },
    {
      query: {
        keepPreviousData: true,
        enabled: !!clusterId,
        onSuccess() {
          setFirstLoadDone(true)
        }
      }
    }
  )

  const showLoadMore = useMemo(() => {
    if (!data || !data.total) return false

    const total = Number(data.total)
    if (isFetched && pagination.size >= total) return false

    return true
  }, [data, pagination.size, isFetched])

  const [cancelModal, setCancelModal] = useState<{
    open: boolean
    export?: DataflowBackupExport
  }>({
    open: false
  })

  const cancelBackupExportMutation = useCancelBackupExport()
  const onCancelBackupExport = useMemoizedFn(async (data: DataflowBackupExport) => {
    try {
      await cancelBackupExportMutation.mutateAsync({
        orgId: orgId,
        projectId: projectId,
        clusterId: clusterId!,
        backupId: data.backup_id!,
        exportId: data.id!,
        data: {
          reason: 'User requested cancellation'
        }
      })
      notifier.success('Backup export cancelled successfully')

      setCancelModal({ open: false })
      refetch()
    } catch (error) {
      notifier.error(getErrorMessage(error))
    }
  })

  const onCancel = useMemoizedFn((data: DataflowBackupExport) => {
    setCancelModal({ open: true, export: data })
  })
  const onLoadMore = useMemoizedFn(() => {
    if (isFetching) return

    setPagination((prev) => ({ ...prev, page: prev.page + 1, size: PER_PAGE * (prev.page + 1) }))
  })

  if (isLoading && !firstLoadDone) {
    return (
      <Center>
        <Loader size="xs" />
      </Center>
    )
  }

  if (data?.items?.length === 0) {
    return (
      <Center mih="calc(100vh - 100px)">
        <Stack align="center" gap={8}>
          <Typography fw={700} ta="center" fz={18} c="carbon.7">
            No backup exports found
          </Typography>
          <Typography sx={{ textWrap: 'balance' }} ta="center" c="carbon.7">
            To export a backup, select it from the table and click the three-dot menu to start the export process
          </Typography>
        </Stack>
      </Center>
    )
  }

  return (
    <Stack>
      {data?.items?.map((item) => <ExportedBackupCard key={item.id} data={item} onCancel={onCancel} />)}
      {showLoadMore && (
        <Center>
          <Anchor onClick={onLoadMore}>{isFetching ? 'Loading...' : 'Load more'}</Anchor>
        </Center>
      )}

      <Modal
        opened={cancelModal.open}
        size="lg"
        onClose={() => setCancelModal({ open: false })}
        title="Cancel Backup Export"
      >
        <Typography>
          You are about to cancel the export of backup{' '}
          <Typography
            px={4}
            py={2}
            bg="carbon.3"
            span
            sx={{ borderRadius: 4, border: '1px solid var(--mantine-color-carbon-5)' }}
          >
            {cancelModal.export?.backup_name ?? cancelModal.export?.backup_id}
          </Typography>
          . Please note that some partially exported files may remain in your bucket after cancellation. Do you want to
          proceed?
        </Typography>

        <Group justify="flex-end" mt={16}>
          <Button variant="default" onClick={() => setCancelModal({ open: false })}>
            No
          </Button>
          <Button
            loading={cancelBackupExportMutation.isLoading}
            onClick={() => onCancelBackupExport(cancelModal.export!)}
          >
            Yes, cancel it
          </Button>
        </Group>
      </Modal>
    </Stack>
  )
})
