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

import {
  useGetDMJob,
  useGetDMOverview,
  useGetDMPrecheck,
  useListDMJobs,
  useListDMPrechecks
} from '../hooks'
import { strings } from '../strings'
import { useToolsPage } from '../ToolsPageContext'
import { isNextGenDeployType, type DMJob, type DMPrecheck } from '../types'
import { formatTs, statusBadge } from '../utils'

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

function DMOverviewPanel() {
  const { clusterId } = useToolsPage()
  const { data, isLoading, isError } = useGetDMOverview(clusterId)
  return (
    <Card
      title="DM Overview"
      size="small"
      bordered={false}
      headStyle={{ backgroundColor: '#fafafa' }}
      style={{ marginBottom: 16 }}
    >
      {isError && <Alert type="error" message={strings.common.errorPanel} />}
      {isLoading && <div>Loading…</div>}
      {data && (
        <Descriptions size="small" column={2}>
          <Descriptions.Item label="Version">{data.version}</Descriptions.Item>
          <Descriptions.Item label="Version Source">
            {data.version_source}
          </Descriptions.Item>
        </Descriptions>
      )}
    </Card>
  )
}

function JobDetailDrawer({
  open,
  jobId,
  onClose
}: {
  open: boolean
  jobId?: string
  onClose: () => void
}) {
  const { clusterId, deployType } = useToolsPage()
  const isNextGen = isNextGenDeployType(deployType)
  const { data, isLoading } = useGetDMJob(clusterId, jobId, open)
  return (
    <Drawer
      open={open}
      onClose={onClose}
      width={640}
      title={data ? 'DM Job: ' + data.name : 'DM Job'}
    >
      {isLoading && <div>Loading…</div>}
      {!isLoading && !data && <div>{strings.common.empty}</div>}
      {data && (
        <Space direction="vertical" style={{ width: '100%' }}>
          <div>
            <b>ID:</b> {data.id}
          </div>
          <div>
            <b>Status:</b> {statusBadge(data.status)}
          </div>
          {!isNextGen && (
            <div>
              <b>Source:</b> {data.source_type}
            </div>
          )}
          {!isNextGen && (
            <div>
              <b>Target Cluster:</b> {data.target_cluster}
            </div>
          )}
          <div>
            <b>Mode:</b> {data.mode}
          </div>
          {data.conn_method && (
            <div>
              <b>Connection Method:</b> {data.conn_method}
            </div>
          )}
          {data.error_msg && <Alert type="error" message={data.error_msg} />}
          <Typography.Title level={5}>Sub-tasks</Typography.Title>
          <Table
            size="small"
            rowKey={(_, i) => String(i)}
            pagination={false}
            dataSource={data.sub_tasks}
            columns={[
              ...(!isNextGen ? [{ title: 'Name', dataIndex: 'name' }] : []),
              { title: 'Mode', dataIndex: 'mode' },
              {
                title: 'Status',
                dataIndex: 'status',
                render: (v: string) => statusBadge(v)
              },
              {
                title: 'Progress',
                dataIndex: 'progress_percent',
                render: (v: number | undefined) =>
                  v === undefined ? '—' : v + '%'
              },
              {
                title: 'Binlog Pos',
                dataIndex: 'binlog_position',
                render: (v: string) => v || '—'
              },
              {
                title: 'Rows/s',
                dataIndex: 'rows_per_sec',
                render: (v: number | undefined) =>
                  v === undefined ? '—' : v.toLocaleString()
              }
            ]}
          />
        </Space>
      )}
    </Drawer>
  )
}

function PrecheckDetailModal({
  open,
  precheckId,
  onClose
}: {
  open: boolean
  precheckId?: string
  onClose: () => void
}) {
  const { clusterId } = useToolsPage()
  const { data, isLoading } = useGetDMPrecheck(clusterId, precheckId, open)
  return (
    <Modal
      open={open}
      onCancel={onClose}
      onOk={onClose}
      width={720}
      title={data ? 'Precheck: ' + (data.dm_job_name || data.id) : 'Precheck'}
      footer={null}
    >
      {isLoading && <div>Loading…</div>}
      {!isLoading && !data && <div>{strings.common.empty}</div>}
      {data && (
        <Table
          size="small"
          rowKey="name"
          pagination={false}
          dataSource={data.items}
          columns={[
            { title: 'Check', dataIndex: 'name' },
            {
              title: 'Status',
              dataIndex: 'status',
              filters: [
                { text: 'passed', value: 'passed' },
                { text: 'warning', value: 'warning' },
                { text: 'failed', value: 'failed' },
                { text: 'running', value: 'running' }
              ],
              onFilter: (value, record) => record.status === value,
              render: (v) => statusBadge(v)
            },
            { title: 'Result', dataIndex: 'result' },
            {
              title: 'Error',
              dataIndex: 'errmsg',
              render: (v) =>
                v ? <span style={{ color: '#f5222d' }}>{v}</span> : '—'
            }
          ]}
        />
      )}
    </Modal>
  )
}

function JobsTable() {
  const { clusterId, deployType } = useToolsPage()
  const isNextGen = isNextGenDeployType(deployType)
  const [page, setPage] = useState(1)
  const [pageSize, setPageSize] = useState(20)
  const listParams = isNextGen
    ? {
        // The Premium DM API is page-token based, but devops does not expose its token.
        // Fetch its maximum supported page to avoid showing duplicate numbered pages.
        page: 1,
        page_size: 100
      }
    : { page, page_size: pageSize }
  const { data, isLoading, isError } = useListDMJobs(clusterId, listParams)
  const [openJobId, setOpenJobId] = useState<string | undefined>()

  const columns: ColumnsType<DMJob> = [
    { title: 'ID', dataIndex: 'id', width: 100 },
    { title: 'Job Name', dataIndex: 'name' },
    {
      title: 'Status',
      dataIndex: 'status',
      render: (v) => statusBadge(v)
    },
    ...(!isNextGen
      ? ([{ title: 'Source', dataIndex: 'source_type' }] as ColumnsType<DMJob>)
      : []),
    { title: 'Mode', dataIndex: 'mode' },
    ...(!isNextGen
      ? ([
          {
            title: 'Conn Method',
            dataIndex: 'conn_method',
            render: (v: string) => v || '—'
          }
        ] as ColumnsType<DMJob>)
      : []),
    {
      title: 'Error',
      dataIndex: 'error_msg',
      render: (v) => (v ? <span style={{ color: '#f5222d' }}>{v}</span> : '—')
    },
    {
      title: 'Created',
      dataIndex: 'created_at',
      render: (v) => formatTs(v)
    },
    {
      title: 'Last Update',
      dataIndex: 'updated_at',
      render: (v) => formatTs(v)
    },
    {
      title: 'Action',
      key: 'action',
      render: (_, record) => (
        <Button
          type="link"
          size="small"
          style={{ padding: '0 4px' }}
          onClick={() => setOpenJobId(record.id)}
        >
          Detail
        </Button>
      )
    }
  ]

  return (
    <>
      {isError && <Alert type="error" message={strings.common.errorPanel} />}
      <Table<DMJob>
        rowKey="id"
        size="small"
        loading={isLoading}
        dataSource={(data?.items || []) as DMJob[]}
        columns={columns}
        pagination={
          isNextGen
            ? false
            : {
                current: page,
                pageSize,
                total: data?.total || 0,
                pageSizeOptions: PAGE_SIZE_OPTS,
                showSizeChanger: true,
                onChange: (p, ps) => {
                  setPage(p)
                  setPageSize(ps || pageSize)
                }
              }
        }
      />
      <JobDetailDrawer
        open={!!openJobId}
        jobId={openJobId}
        onClose={() => setOpenJobId(undefined)}
      />
    </>
  )
}

function PrechecksTable() {
  const { clusterId, deployType } = useToolsPage()
  const isNextGen = isNextGenDeployType(deployType)
  const [page, setPage] = useState(1)
  const [pageSize, setPageSize] = useState(20)
  const listParams = isNextGen
    ? {
        // The Premium DM API is page-token based, but devops does not expose its token.
        // Fetch its maximum supported page to avoid showing duplicate numbered pages.
        page: 1,
        page_size: 100
      }
    : { page, page_size: pageSize }
  const { data, isLoading, isError, error } = useListDMPrechecks(
    clusterId,
    listParams
  )
  const [openId, setOpenId] = useState<string | undefined>()

  const status501 =
    (error as { response?: { status?: number } } | undefined)?.response
      ?.status === 501

  const progressTitle = (
    <Tooltip title="finished = items completed; total = total check items">
      Progress
    </Tooltip>
  )

  const columns: ColumnsType<DMPrecheck> = [
    { title: 'ID', dataIndex: 'id', width: 100 },
    {
      title: 'Status',
      dataIndex: 'status',
      render: (v) => statusBadge(v)
    },
    {
      title: progressTitle,
      key: 'progress',
      render: (_, r) =>
        r.total !== undefined ? `${r.finished ?? 0} / ${r.total}` : '—'
    },
    {
      title: 'Error',
      dataIndex: 'errmsg',
      render: (v) => (v ? <span style={{ color: '#f5222d' }}>{v}</span> : '—')
    },
    {
      title: 'Started',
      dataIndex: 'started_at',
      render: (v) => formatTs(v)
    },
    {
      title: 'Finished Items',
      key: 'finished',
      render: (_, r) => (r.finished !== undefined ? r.finished : '—')
    },
    {
      title: 'Action',
      key: 'action',
      render: (_, record) => (
        <Button
          type="link"
          size="small"
          style={{ padding: '0 4px' }}
          onClick={() => setOpenId(record.id)}
        >
          Detail
        </Button>
      )
    }
  ]

  return (
    <>
      {status501 && (
        <div style={{ color: '#999' }}>
          Precheck history is not yet available for this environment.
        </div>
      )}
      {isError && !status501 && (
        <Alert type="error" message={strings.common.errorPanel} />
      )}
      {!status501 && (
        <Table<DMPrecheck>
          rowKey="id"
          size="small"
          loading={isLoading}
          dataSource={(data?.items || []) as DMPrecheck[]}
          columns={columns}
          pagination={
            isNextGen
              ? false
              : {
                  current: page,
                  pageSize,
                  total: data?.total || 0,
                  pageSizeOptions: PAGE_SIZE_OPTS,
                  showSizeChanger: true,
                  onChange: (p, ps) => {
                    setPage(p)
                    setPageSize(ps || pageSize)
                  }
                }
          }
        />
      )}
      <PrecheckDetailModal
        open={!!openId}
        precheckId={openId}
        onClose={() => setOpenId(undefined)}
      />
    </>
  )
}

export default function DMPanel() {
  const { deployType } = useToolsPage()
  const isNextGen = isNextGenDeployType(deployType)
  return (
    <div>
      {!isNextGen && <DMOverviewPanel />}
      <Card size="small" bordered={false}>
        <Tabs
          defaultActiveKey="jobs"
          size="small"
          tabBarStyle={{ marginBottom: 12 }}
        >
          <Tabs.TabPane tab="Jobs" key="jobs">
            <JobsTable />
          </Tabs.TabPane>
          <Tabs.TabPane tab="Prechecks" key="prechecks">
            <PrechecksTable />
          </Tabs.TabPane>
        </Tabs>
      </Card>
    </div>
  )
}
