import { Alert, Form, Input, Select } from 'antd'
import { useEffect, useState } from 'react'
import semver from 'semver'

import {
  cloudConfigControllerGetInternalTiCDCCluster,
  cloudConfigControllerListAvailableComponentVersions,
  cloudConfigControllerListInternalChangefeeds
} from 'apiClient/services/devops'
import { CloudconfigClusterType } from 'apiClient/services/devops/interface'

export type VersionFormType = {
  version: string
}

const acknowledgeKeyword = 'confirm'
const alignedWrapperCol = { span: 18, offset: 6 }

const VersionForm = ({
  current,
  component,
  cluster_id,
  cluster_type
}: {
  current?: string
  component: string
  cluster_id?: string
  cluster_type: string
}) => {
  const [versions, setVersions] = useState<string[] | undefined>([])
  const [needUpgradeCDC, setNeedUpgradeCDC] = useState<boolean | null>(false)
  const [targetVersion, setTargetVersion] = useState<string>()

  useEffect(() => {
    const getAvailableVersions = async () => {
      try {
        // FIX ME WHEN SERVERLESS IS NEEDED
        const resp = (
          await cloudConfigControllerListAvailableComponentVersions(component)
        ).data.versions
        setVersions(resp?.reverse())
      } catch (e) {
        console.error(e)
      }
    }

    getAvailableVersions()
  }, [component])

  useEffect(() => {
    let cancelled = false
    const setNeedUpgradeCDCSafely = (value: boolean | null) => {
      if (!cancelled) {
        setNeedUpgradeCDC(value)
      }
    }

    const checkCDCVersion = async () => {
      if (!targetVersion || !cluster_id || !cluster_type) {
        setNeedUpgradeCDCSafely(false)
        return
      }

      if (component !== 'tidb') {
        setNeedUpgradeCDCSafely(false)
        return
      }

      if (cluster_type !== CloudconfigClusterType.DEDICATED_TIDB) {
        setNeedUpgradeCDCSafely(false)
        return
      }

      setNeedUpgradeCDCSafely(null)

      try {
        const baseTargetVersion = semver.coerce(targetVersion)
        if (!baseTargetVersion) {
          console.error('Failed to parse target version:', targetVersion)
          setNeedUpgradeCDCSafely(false)
          return
        }

        const changefeeds = (
          await cloudConfigControllerListInternalChangefeeds(
            cluster_type,
            cluster_id
          )
        ).data.changefeeds

        const ticdcClusterIds = Array.from(
          new Set(
            (changefeeds || [])
              .map((changefeed) => changefeed.ticdc_cluster?.id)
              .filter((id): id is string => Boolean(id))
          )
        )

        if (ticdcClusterIds.length === 0) {
          setNeedUpgradeCDCSafely(false)
          return
        }

        let shouldUpgradeCDC = false
        for (const ticdcClusterId of ticdcClusterIds) {
          try {
            const ticdcCluster = (
              await cloudConfigControllerGetInternalTiCDCCluster(
                CloudconfigClusterType.TICDC,
                ticdcClusterId
              )
            ).data.ticdc_cluster
            const cdcVersion = semver.coerce(ticdcCluster?.version || '')

            if (!cdcVersion) {
              console.error(
                `Failed to parse TiCDC version for cluster ${ticdcClusterId}:`,
                ticdcCluster?.version
              )
              continue
            }

            if (semver.lt(cdcVersion, baseTargetVersion)) {
              shouldUpgradeCDC = true
              break
            }
          } catch (e) {
            console.error(
              `Failed to load TiCDC cluster detail for ${ticdcClusterId}:`,
              e
            )
          }
        }

        setNeedUpgradeCDCSafely(shouldUpgradeCDC)
      } catch (e) {
        console.error(e)
        setNeedUpgradeCDCSafely(false)
      }
    }

    checkCDCVersion()

    return () => {
      cancelled = true
    }
  }, [component, targetVersion, cluster_id, cluster_type])

  return (
    <>
      {current !== undefined ? (
        <Form.Item name="curVersion" label="Current Version">
          <Input
            disabled={true}
            bordered={false}
            style={{ color: 'black' }}
          ></Input>
        </Form.Item>
      ) : (
        <></>
      )}
      <Form.Item
        name="version"
        label="Target Version"
        rules={[
          { required: true },
          {
            validator: async () => {
              if (needUpgradeCDC === null) {
                throw new Error('Checking TiCDC version, please wait.')
              }
            }
          }
        ]}
      >
        <Select
          style={{ width: '50%' }}
          options={versions?.map((v) => {
            return { label: v, value: v }
          })}
          onChange={(value) => {
            setTargetVersion(value)
          }}
        ></Select>
      </Form.Item>

      {needUpgradeCDC === null ? (
        <Form.Item wrapperCol={alignedWrapperCol}>
          <Alert
            message="Checking TiCDC cluster versions..."
            type="info"
            showIcon
          />
        </Form.Item>
      ) : null}

      {needUpgradeCDC === true ? (
        <>
          <Form.Item
            wrapperCol={alignedWrapperCol}
            style={{ marginBottom: 12 }}
          >
            <Alert
              message={
                <>
                  {`At least one TiCDC cluster version is lower than target version '${targetVersion}'. Please go to the corresponding TiCDC Page and upgrade the TiCDC clusters first.`}
                  <br />
                  {`If you acknowledge this impact and still want to continue, enter "${acknowledgeKeyword}" below.`}
                </>
              }
              type="warning"
              showIcon
            />
          </Form.Item>
          <Form.Item
            name="confirmKeyword"
            wrapperCol={alignedWrapperCol}
            validateFirst
            rules={[
              {
                required: true,
                message: `Please enter "${acknowledgeKeyword}" to continue`
              },
              {
                validator: (_, value) => {
                  if (
                    typeof value === 'string' &&
                    value.trim() === acknowledgeKeyword
                  ) {
                    return Promise.resolve()
                  }

                  return Promise.reject(
                    new Error(
                      `Please enter "${acknowledgeKeyword}" to continue`
                    )
                  )
                }
              }
            ]}
          >
            <Input
              placeholder={`Please enter "${acknowledgeKeyword}" after you acknowledge`}
            />
          </Form.Item>
        </>
      ) : (
        <></>
      )}
    </>
  )
}

export default VersionForm
