import { PlusOutlined } from '@ant-design/icons'
import { Button, DatePicker, Form, Modal, Space, Table, message } from 'antd'
import type { ColumnsType } from 'antd/lib/table'
import { Moment } from 'moment'
import moment from 'moment'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { Link } from 'react-router-dom'

import {
  k8sUpgradePlanControllerCancelPlan,
  k8sUpgradePlanControllerCreatePlan,
  k8sUpgradePlanControllerGetPlan,
  k8sUpgradePlanControllerListPlans,
  k8sUpgradePlanControllerSchedulePlan,
  k8sUpgradePlanControllerTriggerNow,
  k8sUpgradePlanControllerUpdatePlan
} from 'apiClient/services/devops'
import type {
  K8supgradeplanCreatePlanReq,
  K8supgradeplanPlannedUpgrade,
  K8supgradeplanPlanStatus,
  K8supgradeplanUpdatePlanReq
} from 'apiClient/services/devops/interface'
import { K8supgradeplanPlanStatus as PlanStatusEnum } from 'apiClient/services/devops/interface'
import ModalForm from 'components/ModalForm'
import { ListToolBar } from 'components/Table'

import { toLocal } from '../Maintenance/Detail'

import PlanDetailModal from './PlanDetailModal'
import PlanFormFields from './PlanFormFields'
import {
  EosVersionHighlight,
  formatEosDate,
  renderPlanStatusTag
} from './utils'

import './index.less'

const LIST_PAGE_SIZE = 100

const TERMINAL_STATUS_SET = new Set([
  PlanStatusEnum.task_created,
  PlanStatusEnum.rejected,
  PlanStatusEnum.cancelled,
  'task_created',
  'rejected',
  'cancelled'
])

const normalizePlanStatus = (status?: string) => (status ?? '').toLowerCase()

const isTerminalPlanStatus = (status?: string) =>
  TERMINAL_STATUS_SET.has(normalizePlanStatus(status))

const compareNumber = (a?: number, b?: number) => (a ?? 0) - (b ?? 0)

const compareString = (a?: string, b?: string) =>
  (a ?? '').localeCompare(b ?? '', undefined, { numeric: true })

const fetchAllPlans = async (): Promise<K8supgradeplanPlannedUpgrade[]> => {
  const items: K8supgradeplanPlannedUpgrade[] = []
  let page = 1
  let total = 0

  do {
    const resp = await k8sUpgradePlanControllerListPlans({
      page,
      per_page: LIST_PAGE_SIZE
    })
    const batch = resp.data?.items ?? []
    total = resp.data?.total ?? batch.length
    items.push(...batch)
    if (batch.length === 0) {
      break
    }
    page += 1
  } while (items.length < total)

  return items
}

/** Schedule API 仅 draft；scheduled 等状态通过 UpdatePlan 改 trigger_time */
const usesScheduleApi = (status: string) => status === PlanStatusEnum.draft

const getPlanActionFlags = (record: K8supgradeplanPlannedUpgrade) => {
  const status = normalizePlanStatus(record.status)
  const isTerminal = isTerminalPlanStatus(record.status)
  const canCancel = Boolean(record.status && !isTerminal)

  return {
    canUpdate:
      status === PlanStatusEnum.draft || status === PlanStatusEnum.scheduled,
    canSchedule:
      canCancel &&
      (usesScheduleApi(status) ||
        status === PlanStatusEnum.scheduled ||
        status === PlanStatusEnum.approved ||
        status === 'upgrading'),
    canTriggerNow: canCancel && !record.linked_task_id,
    canCancel
  }
}

type PlanFormValues = {
  name: string
  cloud_provider?: string
  eos_version?: string
  eos_date?: Moment
  deadline: Moment
  trigger_time?: Moment
  max_restart_times?: number
  selector_type?: string
  selector_value?: string
  selector_values?: string[]
}

type ScheduleFormValues = {
  trigger_time: Moment
}

const buildSelectorValue = (values: PlanFormValues): string | undefined => {
  const selectorType = values.selector_type ?? 'none'
  if (
    selectorType === 'by_tenant_ids' ||
    selectorType === 'by_project_ids' ||
    selectorType === 'by_tidb_cluster_ids' ||
    selectorType === 'by_k8s_names'
  ) {
    const list = (values.selector_values ?? []).filter(Boolean)
    return list.length > 0 ? list.join(',') : undefined
  }
  if (selectorType === 'by_region') {
    return values.selector_value
  }
  return undefined
}

const K8sUpgradePlan = () => {
  const [plans, setPlans] = useState<K8supgradeplanPlannedUpgrade[]>([])
  const [loading, setLoading] = useState(false)
  const [createOpen, setCreateOpen] = useState(false)
  const [editPlan, setEditPlan] = useState<K8supgradeplanPlannedUpgrade | null>(
    null
  )
  const [schedulePlan, setSchedulePlan] =
    useState<K8supgradeplanPlannedUpgrade | null>(null)
  const [detailPlan, setDetailPlan] =
    useState<K8supgradeplanPlannedUpgrade | null>(null)
  const [detailLoading, setDetailLoading] = useState(false)

  const reload = useCallback(async () => {
    setLoading(true)
    try {
      setPlans(await fetchAllPlans())
    } catch (e) {
      console.error(e)
    } finally {
      setLoading(false)
    }
  }, [])

  useEffect(() => {
    reload()
  }, [reload])

  const eosVersionFilterOptions = useMemo(() => {
    const versions = new Set<string>()
    plans.forEach((p) => {
      if (p.eos_version) {
        versions.add(p.eos_version)
      }
    })
    return Array.from(versions)
      .sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
      .map((v) => ({ text: v, value: v }))
  }, [plans])

  const runAction = useCallback(
    (title: string, action: () => Promise<unknown>, successMessage: string) => {
      Modal.confirm({
        title,
        onOk: async () => {
          await action()
          message.success(successMessage)
          await reload()
        }
      })
    },
    [reload]
  )

  const openDetail = useCallback(
    async (record: K8supgradeplanPlannedUpgrade) => {
      if (!record.id) return
      setDetailLoading(true)
      setDetailPlan(record)
      try {
        const resp = await k8sUpgradePlanControllerGetPlan(record.id)
        setDetailPlan(resp.data ?? record)
      } finally {
        setDetailLoading(false)
      }
    },
    []
  )

  const handleCreate = useCallback(
    async (values: PlanFormValues) => {
      const req: K8supgradeplanCreatePlanReq = {
        name: values.name,
        cloud_provider: values.cloud_provider!,
        eos_version: values.eos_version!,
        eos_date: values.eos_date!.unix(),
        deadline: values.deadline.unix(),
        max_restart_times: values.max_restart_times,
        selector_type: values.selector_type,
        selector_value: buildSelectorValue(values),
        trigger_time: values.trigger_time?.unix()
      }
      await k8sUpgradePlanControllerCreatePlan(req)
      setCreateOpen(false)
      await reload()
    },
    [reload]
  )

  const handleUpdate = useCallback(
    async (values: PlanFormValues) => {
      if (!editPlan?.id) return
      const req: K8supgradeplanUpdatePlanReq = {
        name: values.name,
        deadline: values.deadline.unix(),
        max_restart_times: values.max_restart_times,
        selector_type: values.selector_type,
        selector_value: buildSelectorValue(values),
        trigger_time: values.trigger_time?.unix()
      }
      await k8sUpgradePlanControllerUpdatePlan(editPlan.id, req)
      setEditPlan(null)
      await reload()
    },
    [editPlan?.id, reload]
  )

  const handleSchedule = useCallback(
    async (values: ScheduleFormValues) => {
      if (!schedulePlan?.id) return
      const triggerTime = values.trigger_time.unix()
      const status = normalizePlanStatus(schedulePlan.status)
      if (usesScheduleApi(status)) {
        await k8sUpgradePlanControllerSchedulePlan(schedulePlan.id, {
          trigger_time: triggerTime
        })
      } else {
        await k8sUpgradePlanControllerUpdatePlan(schedulePlan.id, {
          trigger_time: triggerTime
        })
      }
      setSchedulePlan(null)
      await reload()
    },
    [schedulePlan, reload]
  )

  const handleTriggerNow = useCallback(
    (record: K8supgradeplanPlannedUpgrade) => {
      if (!record.id) return
      const status = normalizePlanStatus(record.status)
      let hint = 'Create the K8s upgrade task from this plan immediately?'
      if (status === PlanStatusEnum.draft) {
        hint = 'Submit this plan for approval immediately?'
      } else if (
        status === PlanStatusEnum.approving ||
        status === 'upgrading'
      ) {
        hint =
          'Trigger this plan now? (If approval is still in progress, the backend may reject the request.)'
      }
      runAction(
        hint,
        () => k8sUpgradePlanControllerTriggerNow(record.id!),
        'Plan triggered'
      )
    },
    [runAction]
  )

  const renderPlanActions = useCallback(
    (record: K8supgradeplanPlannedUpgrade, compact = false) => {
      const { canUpdate, canSchedule, canTriggerNow, canCancel } =
        getPlanActionFlags(record)

      return (
        <Space size="small" wrap className="k8s-upgrade-plan-actions">
          {!compact && (
            <Button type="link" size="small" onClick={() => openDetail(record)}>
              Detail
            </Button>
          )}
          {canUpdate && (
            <Button
              type="link"
              size="small"
              onClick={() => setEditPlan(record)}
            >
              Edit
            </Button>
          )}
          {canSchedule && (
            <Button
              type="primary"
              size="small"
              ghost
              onClick={() => setSchedulePlan(record)}
            >
              Schedule
            </Button>
          )}
          {canTriggerNow && (
            <Button
              type="primary"
              size="small"
              onClick={() => handleTriggerNow(record)}
            >
              Trigger Now
            </Button>
          )}
          {canCancel && (
            <Button
              type="link"
              size="small"
              danger
              onClick={() =>
                runAction(
                  'Cancel this upgrade plan?',
                  () => k8sUpgradePlanControllerCancelPlan(record.id!),
                  'Plan cancelled'
                )
              }
            >
              Cancel
            </Button>
          )}
          {record.linked_task_id ? (
            <Link
              to={`/k8sUpgradeTask/${
                record.linked_task_id
              }?name=${encodeURIComponent(record.name ?? '')}`}
            >
              Task
            </Link>
          ) : null}
        </Space>
      )
    },
    [handleTriggerNow, openDetail, runAction]
  )

  const renderActions = useCallback(
    (_: unknown, record: K8supgradeplanPlannedUpgrade) =>
      renderPlanActions(record),
    [renderPlanActions]
  )

  const columns = useMemo<ColumnsType<K8supgradeplanPlannedUpgrade>>(
    () => [
      {
        title: 'ID',
        dataIndex: 'id',
        width: 72,
        sorter: (a, b) => compareNumber(a.id, b.id)
      },
      {
        title: 'Name',
        dataIndex: 'name',
        width: 160,
        ellipsis: true,
        sorter: (a, b) => compareString(a.name, b.name)
      },
      {
        title: 'Cloud',
        dataIndex: 'cloud_provider',
        width: 88,
        filterMultiple: true,
        filters: [
          { text: 'aws', value: 'aws' },
          { text: 'gcp', value: 'gcp' }
        ],
        onFilter: (value, record) => record.cloud_provider === value
      },
      {
        title: 'EOS Version',
        dataIndex: 'eos_version',
        width: 110,
        filterMultiple: true,
        filters: eosVersionFilterOptions,
        onFilter: (value, record) => record.eos_version === value,
        sorter: (a, b) => compareString(a.eos_version, b.eos_version),
        render: (value: string) =>
          value ? <EosVersionHighlight version={value} /> : '-'
      },
      {
        title: 'EOS Date',
        dataIndex: 'eos_date',
        width: 120,
        render: (value: string | number) => formatEosDate(value)
      },
      {
        title: 'Status',
        dataIndex: 'status',
        width: 120,
        filterMultiple: true,
        filters: [
          ...Object.values(PlanStatusEnum).map((v) => ({
            text: v,
            value: v
          })),
          { text: 'upgrading', value: 'upgrading' }
        ],
        onFilter: (value, record) =>
          normalizePlanStatus(record.status) ===
          normalizePlanStatus(String(value)),
        render: (value: K8supgradeplanPlanStatus) => renderPlanStatusTag(value)
      },
      {
        title: 'Est. Clusters',
        dataIndex: 'estimated_clusters',
        width: 110,
        sorter: (a, b) =>
          compareNumber(a.estimated_clusters, b.estimated_clusters)
      },
      {
        title: 'Deadline',
        dataIndex: 'deadline',
        width: 120,
        sorter: (a, b) => compareNumber(a.deadline, b.deadline),
        render: (value: number) => formatEosDate(value)
      },
      {
        title: 'Trigger Time',
        dataIndex: 'trigger_time',
        width: 120,
        defaultSortOrder: 'ascend',
        sorter: (a, b) => compareNumber(a.trigger_time, b.trigger_time),
        render: (value: number) => formatEosDate(value)
      },
      {
        title: 'Created At',
        dataIndex: 'created_at',
        width: 170,
        sorter: (a, b) => compareNumber(a.created_at, b.created_at),
        render: (value: number) => toLocal(value) || '-'
      },
      {
        title: 'Created By',
        dataIndex: 'created_by',
        width: 180,
        ellipsis: true,
        sorter: (a, b) => compareString(a.created_by, b.created_by)
      },
      {
        title: 'Actions',
        key: 'actions',
        width: 340,
        fixed: 'right',
        render: renderActions
      }
    ],
    [eosVersionFilterOptions, renderActions]
  )

  const editInitValues = useMemo((): Partial<PlanFormValues> | undefined => {
    if (!editPlan) return undefined
    return {
      name: editPlan.name ?? '',
      deadline: editPlan.deadline ? moment.unix(editPlan.deadline) : moment(),
      trigger_time: editPlan.trigger_time
        ? moment.unix(editPlan.trigger_time)
        : undefined,
      max_restart_times: editPlan.max_restart_times,
      selector_type: editPlan.selector_type ?? 'none',
      selector_value: editPlan.selector_value,
      selector_values: editPlan.selector_value
        ? editPlan.selector_value.split(',').filter(Boolean)
        : []
    }
  }, [editPlan])

  const toolbarActions = useMemo(
    () => [
      <Button
        key="create"
        type="primary"
        icon={<PlusOutlined />}
        onClick={() => setCreateOpen(true)}
      >
        Create Plan
      </Button>
    ],
    []
  )

  return (
    <>
      <ListToolBar
        title="K8s Upgrade Plans"
        reload={reload}
        actions={toolbarActions}
      />
      <Table<K8supgradeplanPlannedUpgrade>
        className="k8s-upgrade-plan-table"
        rowKey="id"
        size="small"
        loading={loading}
        columns={columns}
        dataSource={plans}
        scroll={{ x: 1630 }}
        pagination={{
          defaultPageSize: 10,
          showSizeChanger: true,
          pageSizeOptions: ['10', '20', '50', '100']
        }}
      />

      <ModalForm<PlanFormValues>
        visible={createOpen}
        name="k8s-upgrade-plan-create"
        title="Create K8s Upgrade Plan"
        getFields={() => <PlanFormFields mode="create" />}
        onSubmit={handleCreate}
        onCancel={() => setCreateOpen(false)}
      />

      <ModalForm<PlanFormValues>
        visible={!!editPlan}
        name="k8s-upgrade-plan-edit"
        title={`Edit Plan #${editPlan?.id ?? ''}`}
        initValues={editInitValues as PlanFormValues}
        getFields={() => <PlanFormFields mode="edit" />}
        onSubmit={handleUpdate}
        onCancel={() => setEditPlan(null)}
      />

      <ModalForm<ScheduleFormValues>
        visible={!!schedulePlan}
        name="k8s-upgrade-plan-schedule"
        title={`Schedule Plan #${schedulePlan?.id ?? ''}`}
        initValues={{
          trigger_time: schedulePlan?.trigger_time
            ? moment.unix(schedulePlan.trigger_time)
            : moment().add(1, 'day')
        }}
        getFields={() => (
          <Form.Item
            name="trigger_time"
            label="Trigger Time"
            rules={[{ required: true, message: 'Please select trigger time' }]}
            style={{ width: 600 }}
          >
            <DatePicker showTime style={{ width: 280 }} />
          </Form.Item>
        )}
        onSubmit={handleSchedule}
        onCancel={() => setSchedulePlan(null)}
      />

      <PlanDetailModal
        plan={detailPlan}
        loading={detailLoading}
        footerActions={detailPlan ? renderPlanActions(detailPlan, true) : null}
        onClose={() => setDetailPlan(null)}
      />
    </>
  )
}

export default K8sUpgradePlan
