import {
  Alert,
  Button,
  Card,
  Descriptions,
  Drawer,
  Table,
  Tabs,
  Tag,
  Tooltip
} from 'antd'
import type { ColumnsType } from 'antd/lib/table'
import React, { useState } from 'react'

import {
  useGetDedicatedBackupSetting,
  useGetNextGenBackupSetting,
  useListBackups,
  useListLogBackups
} from '../hooks'
import { strings } from '../strings'
import { useToolsPage } from '../ToolsPageContext'
import { isDedicatedDeployType, isNextGenDeployType } from '../types'
import type {
  LogBackup,
  NextGenBackupPolicy,
  NextGenBackupSetting,
  SnapshotBackup
} from '../types'
import { formatBytes, formatTs, statusBadge } from '../utils'

import { ExportTasksTable } from './ExportTasks'

const PAGE_SIZE_OPTS = ['10', '20', '50', '100']

type NextGenSettingRow = {
  policy?: string
  feature: string
  retention: string
  description: string
}

function BackupSettingsPanel() {
  const { clusterId, deployType } = useToolsPage()
  const isNextGen = isNextGenDeployType(deployType)
  const dedicatedQuery = useGetDedicatedBackupSetting(clusterId, !isNextGen)
  const nextGenQuery = useGetNextGenBackupSetting(clusterId, isNextGen)
  const { data, isLoading, isError } = isNextGen ? nextGenQuery : dedicatedQuery
  const dedicatedSetting = dedicatedQuery.data
  return (
    <Card
      title="Backup Settings"
      size="small"
      bordered={false}
      headStyle={{ backgroundColor: '#fafafa' }}
    >
      {isError && <Alert type="error" message={strings.common.errorPanel} />}
      {isLoading && <div>Loading…</div>}
      {nextGenQuery.data?.unavailable && isNextGen && (
        <Alert
          type="info"
          showIcon
          message="Backup settings will be available after the restore completes."
        />
      )}
      {nextGenQuery.data && isNextGen && !nextGenQuery.data.unavailable && (
        <NextGenBackupSettings setting={nextGenQuery.data} />
      )}
      {dedicatedSetting && !isNextGen && (
        <Descriptions size="small" column={2}>
          <Descriptions.Item label="Auto Backup">
            {statusBadge(dedicatedSetting.scheduled_status)}
          </Descriptions.Item>
          <Descriptions.Item label="Schedule">
            {dedicatedSetting.schedule || '—'}
          </Descriptions.Item>
          <Descriptions.Item label="Next Run">
            {dedicatedSetting.next_run_at
              ? formatTs(dedicatedSetting.next_run_at)
              : '—'}
          </Descriptions.Item>
          <Descriptions.Item label="Retention (days)">
            {dedicatedSetting.retention_days}
          </Descriptions.Item>
          <Descriptions.Item label="Dual Region">
            {dedicatedSetting.dual_region_enabled
              ? `Enabled${
                  dedicatedSetting.dual_regions &&
                  dedicatedSetting.dual_regions.length > 0
                    ? ': ' + dedicatedSetting.dual_regions.join(', ')
                    : ''
                }`
              : 'Disabled'}
          </Descriptions.Item>
          <Descriptions.Item label="Log Backup (PiTR)">
            {dedicatedSetting.log_backup_enabled ? 'Enabled' : 'Disabled'}
          </Descriptions.Item>
          {(dedicatedSetting.current_actions?.length ?? 0) > 0 && (
            <Descriptions.Item label="Available Actions" span={2}>
              {dedicatedSetting.current_actions?.join(', ')}
            </Descriptions.Item>
          )}
        </Descriptions>
      )}
    </Card>
  )
}

function NextGenBackupSettings({ setting }: { setting: NextGenBackupSetting }) {
  const isBundle = setting.mode === 'standard_bundle'
  const isFlexibleRetention = setting.mode === 'flexible_retention'
  if (!isBundle && !isFlexibleRetention) {
    return (
      <Alert
        type="warning"
        showIcon
        message="Backup mode is unavailable"
        description="The service did not report a backup retention mode."
      />
    )
  }
  const rows = nextGenSettingRows(setting)
  const policyCatalogUnavailable = isBundle && rows.length === 0

  return (
    <>
      <Descriptions size="small" column={2} style={{ marginBottom: 12 }}>
        <Descriptions.Item label="Auto Backup Mode">
          <Tag color={isBundle ? 'purple' : 'blue'}>
            {isBundle ? 'Standard Bundle' : 'Custom Retention'}
          </Tag>
        </Descriptions.Item>
        {isFlexibleRetention && (
          <>
            <Descriptions.Item label="Backup Retention">
              {setting.retention_days ? `${setting.retention_days} days` : '—'}
            </Descriptions.Item>
            <Descriptions.Item label="Daily Backup Time">
              {setting.daily_backup_time_utc
                ? `${setting.daily_backup_time_utc} UTC`
                : '—'}
            </Descriptions.Item>
          </>
        )}
        <Descriptions.Item label="PITR Window">
          {setting.pitr_start_time && setting.pitr_end_time
            ? `${formatTs(setting.pitr_start_time)} – ${formatTs(
                setting.pitr_end_time
              )}`
            : '—'}
        </Descriptions.Item>
      </Descriptions>
      {policyCatalogUnavailable ? (
        <Alert
          type="info"
          showIcon
          message="Backup policy catalog is unavailable"
          description="The service reported Standard Bundle mode but did not return any backup policies."
        />
      ) : (
        <Table
          rowKey={(row) => `${row.policy || ''}-${row.feature}`}
          size="small"
          pagination={false}
          dataSource={rows}
          columns={[
            ...(isBundle
              ? [{ title: 'Policy', dataIndex: 'policy', width: 140 }]
              : []),
            { title: 'Feature', dataIndex: 'feature' },
            { title: 'Retention', dataIndex: 'retention', width: 130 },
            { title: 'Restore Details', dataIndex: 'description' }
          ]}
        />
      )}
    </>
  )
}

function nextGenSettingRows(
  setting: NextGenBackupSetting
): NextGenSettingRow[] {
  if (setting.mode === 'standard_bundle') {
    return (setting.backup_policies || []).flatMap((policy) =>
      standardBundlePolicyRows(policy)
    )
  }

  const retentionDays = setting.retention_days || undefined
  const retention = retentionDays === undefined ? '—' : `${retentionDays} days`
  const dailyStart = setting.daily_backup_time_utc
  return [
    {
      feature: 'PITR',
      retention,
      description:
        retentionDays === undefined
          ? 'Retention is unavailable because the service did not report it.'
          : `Restore to any specific moment within the ${retentionDays}-day retention period.`
    },
    {
      feature: 'Daily Backup Snapshot',
      retention,
      description:
        retentionDays === undefined || !dailyStart
          ? 'Schedule or retention is unavailable because the service did not report it.'
          : `The ${dailyStart} UTC daily snapshot is available for ${retentionDays} days.`
    }
  ]
}

function standardBundlePolicyRows(
  policy: NextGenBackupPolicy
): NextGenSettingRow[] {
  const retention = (days?: number) =>
    days === undefined ? '—' : `${days} days`
  const pitr = policy.pitr_retention_days
  const hourly = policy.hourly_retention_days
  const daily = policy.daily_retention_days
  const start = policy.daily_start_time_utc
  const unavailable =
    'Retention is unavailable because the policy did not report it.'
  return [
    {
      policy: policy.name || '—',
      feature: 'PITR',
      retention: retention(pitr),
      description:
        pitr === undefined
          ? unavailable
          : `Restore to any specific moment within the ${pitr}-day retention period.`
    },
    {
      policy: policy.name || '—',
      feature: 'Hourly Backup Snapshot',
      retention: retention(hourly),
      description:
        hourly === undefined
          ? unavailable
          : `Each hourly snapshot is available for ${hourly} days.`
    },
    {
      policy: policy.name || '—',
      feature: 'Daily Backup Snapshot',
      retention: retention(daily),
      description:
        daily === undefined || !start
          ? 'Schedule or retention is unavailable because the policy did not report it.'
          : `The ${start} UTC daily snapshot is available for ${daily} days.`
    }
  ]
}

function tsoToDatetime(tso: string | undefined): string {
  if (!tso || tso === '0') return '—'
  try {
    const ms = Number(BigInt(tso) >> BigInt(18))
    return formatTs(ms / 1000)
  } catch {
    return tso
  }
}

function SnapshotBackupsTable() {
  const { clusterId, deployType } = useToolsPage()
  const isNextGen = isNextGenDeployType(deployType)
  const [page, setPage] = useState(1)
  const [pageSize, setPageSize] = useState(20)
  const { data, isLoading, isError } = useListBackups(clusterId, {
    page,
    page_size: pageSize
  })
  const [openBackup, setOpenBackup] = useState<SnapshotBackup | undefined>()

  const dedicatedColumns: ColumnsType<SnapshotBackup> = [
    { title: 'ID', dataIndex: 'id', width: 100 },
    { title: 'Name', dataIndex: 'name' },
    { title: 'Type', dataIndex: 'type' },
    {
      title: 'Status',
      dataIndex: 'status',
      render: (v) => statusBadge(v)
    },
    {
      title: 'TSO',
      dataIndex: 'tso',
      render: (v) =>
        v && v !== '0' ? (
          <Tooltip title={tsoToDatetime(v)}>
            <span style={{ cursor: 'default' }}>{v}</span>
          </Tooltip>
        ) : (
          '—'
        )
    },
    { title: 'Size', dataIndex: 'size_bytes', render: (v) => formatBytes(v) },
    { title: 'Started', dataIndex: 'started_at', render: (v) => formatTs(v) },
    { title: 'Finished', dataIndex: 'finished_at', render: (v) => formatTs(v) },
    {
      title: 'Action',
      key: 'action',
      render: (_, record) => (
        <Button
          type="link"
          size="small"
          style={{ padding: '0 4px' }}
          onClick={() => setOpenBackup(record)}
        >
          Detail
        </Button>
      )
    }
  ]

  const nextGenColumns: ColumnsType<SnapshotBackup> = [
    { title: 'Backup Name', dataIndex: 'name' },
    {
      title: 'Backup Time',
      dataIndex: 'tso',
      render: (v) => tsoToDatetime(v)
    },
    { title: 'Type', dataIndex: 'type', width: 90 },
    { title: 'TSO', dataIndex: 'tso', width: 190 },
    {
      title: 'File Size',
      dataIndex: 'size_bytes',
      render: (v) => formatBytes(v)
    },
    {
      title: 'Status',
      dataIndex: 'status',
      render: (v) => statusBadge(v)
    },
    {
      title: 'Expires In',
      dataIndex: 'expire_at',
      render: (v) => {
        if (!v) return '—'
        const seconds = v - Date.now() / 1000
        return (
          <Tooltip title={`Expires at ${formatTs(v)}`}>
            {seconds <= 0
              ? 'Expired'
              : `${Math.max(0, Math.floor(seconds / 86400))} days`}
          </Tooltip>
        )
      }
    },
    {
      title: 'Action',
      key: 'action',
      width: 80,
      render: (_, record) => (
        <Button
          type="link"
          size="small"
          style={{ padding: '0 4px' }}
          onClick={() => setOpenBackup(record)}
        >
          Detail
        </Button>
      )
    }
  ]

  return (
    <>
      {isError && <Alert type="error" message={strings.common.errorPanel} />}
      <Table<SnapshotBackup>
        rowKey="id"
        size="small"
        loading={isLoading}
        dataSource={(data?.items || []) as SnapshotBackup[]}
        columns={isNextGen ? nextGenColumns : dedicatedColumns}
        pagination={{
          current: page,
          pageSize,
          total: data?.total || 0,
          pageSizeOptions: PAGE_SIZE_OPTS,
          showSizeChanger: true,
          onChange: (p, ps) => {
            setPage(p)
            setPageSize(ps || pageSize)
          }
        }}
      />
      <Drawer
        open={!!openBackup}
        onClose={() => setOpenBackup(undefined)}
        width={520}
        title={openBackup?.name}
      >
        {openBackup && (
          <Descriptions size="small" column={1} bordered>
            <Descriptions.Item label="ID">{openBackup.id}</Descriptions.Item>
            <Descriptions.Item label="Type">
              {openBackup.type}
            </Descriptions.Item>
            <Descriptions.Item label="Status">
              {statusBadge(openBackup.status)}
            </Descriptions.Item>
            <Descriptions.Item label="TSO">
              {openBackup.tso && openBackup.tso !== '0' ? (
                <>
                  {openBackup.tso}
                  <br />
                  <span style={{ color: '#888', fontSize: 12 }}>
                    {tsoToDatetime(openBackup.tso)}
                  </span>
                </>
              ) : (
                '—'
              )}
            </Descriptions.Item>
            {openBackup.cluster_version && (
              <Descriptions.Item label="Cluster Version">
                {openBackup.cluster_version}
              </Descriptions.Item>
            )}
            <Descriptions.Item label="Size">
              {formatBytes(openBackup.size_bytes)}
            </Descriptions.Item>
            <Descriptions.Item label="Started">
              {formatTs(openBackup.started_at)}
            </Descriptions.Item>
            {openBackup.finished_at && (
              <Descriptions.Item label="Finished">
                {formatTs(openBackup.finished_at)}
              </Descriptions.Item>
            )}
            <Descriptions.Item label="Expires At">
              {openBackup.expire_at ? formatTs(openBackup.expire_at) : '—'}
            </Descriptions.Item>
            {!isNextGen && (
              <Descriptions.Item label="Protected">
                {openBackup.protected ? 'Yes' : 'No'}
              </Descriptions.Item>
            )}
            {openBackup.regions && openBackup.regions.length > 0 && (
              <Descriptions.Item label="Regions">
                {openBackup.regions.join(', ')}
              </Descriptions.Item>
            )}
            {openBackup.error_msg && (
              <Descriptions.Item label="Error">
                <span style={{ color: '#f5222d' }}>{openBackup.error_msg}</span>
              </Descriptions.Item>
            )}
          </Descriptions>
        )}
      </Drawer>
    </>
  )
}

function LogBackupsTable() {
  const { clusterId } = useToolsPage()
  const [page, setPage] = useState(1)
  const [pageSize, setPageSize] = useState(20)
  const { data, isLoading, isError } = useListLogBackups(clusterId, {
    page,
    page_size: pageSize
  })
  const [openLogBackup, setOpenLogBackup] = useState<LogBackup | undefined>()

  const columns: ColumnsType<LogBackup> = [
    { title: 'ID', dataIndex: 'id', width: 100 },
    { title: 'Name', dataIndex: 'name' },
    {
      title: 'Status',
      dataIndex: 'status',
      render: (v) => statusBadge(v)
    },
    {
      title: 'Checkpoint',
      dataIndex: 'checkpoint_timestamp',
      render: (v) => formatTs(v)
    },
    {
      title: 'Truncate Until',
      dataIndex: 'truncate_until',
      render: (v) => (v ? formatTs(v) : '—')
    },
    { title: 'Started', dataIndex: 'started_at', render: (v) => formatTs(v) },
    {
      title: 'Action',
      key: 'action',
      render: (_, record) => (
        <Button
          type="link"
          size="small"
          style={{ padding: '0 4px' }}
          onClick={() => setOpenLogBackup(record)}
        >
          Detail
        </Button>
      )
    }
  ]

  return (
    <>
      {isError && <Alert type="error" message={strings.common.errorPanel} />}
      <Table<LogBackup>
        rowKey="id"
        size="small"
        loading={isLoading}
        dataSource={(data?.items || []) as LogBackup[]}
        columns={columns}
        pagination={{
          current: page,
          pageSize,
          total: data?.total || 0,
          pageSizeOptions: PAGE_SIZE_OPTS,
          showSizeChanger: true,
          onChange: (p, ps) => {
            setPage(p)
            setPageSize(ps || pageSize)
          }
        }}
      />
      <Drawer
        open={!!openLogBackup}
        onClose={() => setOpenLogBackup(undefined)}
        width={520}
        title={openLogBackup?.name}
      >
        {openLogBackup && (
          <Descriptions size="small" column={1} bordered>
            <Descriptions.Item label="ID">{openLogBackup.id}</Descriptions.Item>
            <Descriptions.Item label="Name">
              {openLogBackup.name}
            </Descriptions.Item>
            <Descriptions.Item label="Status">
              {statusBadge(openLogBackup.status)}
            </Descriptions.Item>
            <Descriptions.Item label="Checkpoint">
              {formatTs(openLogBackup.checkpoint_timestamp)}
            </Descriptions.Item>
            <Descriptions.Item label="Truncate Until">
              {openLogBackup.truncate_until
                ? formatTs(openLogBackup.truncate_until)
                : '—'}
            </Descriptions.Item>
            <Descriptions.Item label="Size">
              {openLogBackup.size_bytes
                ? formatBytes(openLogBackup.size_bytes)
                : '—'}
            </Descriptions.Item>
            <Descriptions.Item label="Created">
              {openLogBackup.created_at
                ? formatTs(openLogBackup.created_at)
                : '—'}
            </Descriptions.Item>
            <Descriptions.Item label="Started">
              {formatTs(openLogBackup.started_at)}
            </Descriptions.Item>
            {openLogBackup.regions && openLogBackup.regions.length > 0 && (
              <Descriptions.Item label="Regions">
                {openLogBackup.regions.join(', ')}
              </Descriptions.Item>
            )}
            {openLogBackup.error_msg && (
              <Descriptions.Item label="Error">
                <span style={{ color: '#f5222d' }}>
                  {openLogBackup.error_msg}
                </span>
              </Descriptions.Item>
            )}
          </Descriptions>
        )}
      </Drawer>
    </>
  )
}

export default function BackupPanel() {
  const { deployType } = useToolsPage()
  const showLogBackups = isDedicatedDeployType(deployType)
  const isNextGen = isNextGenDeployType(deployType)
  return (
    <div>
      <BackupSettingsPanel />
      <Card size="small" bordered={false} style={{ marginTop: 16 }}>
        <Tabs
          defaultActiveKey="snapshots"
          size="small"
          tabBarStyle={{ marginBottom: 12 }}
        >
          <Tabs.TabPane
            tab={isNextGen ? 'Backups' : 'Snapshot Backups'}
            key="snapshots"
          >
            <SnapshotBackupsTable />
          </Tabs.TabPane>
          {showLogBackups && (
            <Tabs.TabPane tab="Log Backups" key="log">
              <LogBackupsTable />
            </Tabs.TabPane>
          )}
          {showLogBackups && (
            <Tabs.TabPane tab="Backup Exports" key="exports">
              <ExportTasksTable mode="backup-export" />
            </Tabs.TabPane>
          )}
        </Tabs>
      </Card>
    </div>
  )
}
