import { Button, FormInstance, Input, Modal, Select, Table } from 'antd'
import { ColumnsType } from 'antd/lib/table'
import { useCallback, useEffect, useMemo, useState } from 'react'
import * as semver from 'semver'

import {
  addConfigAttribute,
  cloudConfigControllerCloneParameterAttribute,
  cloudConfigControllerCreateParameterAttribute,
  cloudConfigControllerListParameterVersions,
  cloudConfigControllerListConfigTypes,
  cloudConfigControllerListParameterAttributes,
  cloudConfigControllerUpdateParameterAttribute
} from 'apiClient/services/devops'
import {
  CloudconfigClusterType,
  CloudconfigParameterApplyPolicy,
  CloudconfigParameterAttribute,
  ConfigcenterCopyFromVersionReq
} from 'apiClient/services/devops/interface'
import CodeValue from 'components/CodeValue'
import ConfigName from 'components/ConfigName'
import ModalForm from 'components/ModalForm'
import { ListToolBar, useTable } from 'components/Table'
import { parseFormValue } from 'pages/Tenants/ClusterDetail/Configs/CurrentConfig/Current'
import { convertToString } from 'pages/Tenants/ClusterDetail/Configs/Forms/PreviewForm'

import AddConfigForm, { AddConfigFormType } from './forms/AddForm'
import CopyConfigForm from './forms/CopyForm'
import ModifyConfigForm, { ModifyConfigFormType } from './forms/ModifyForm'

const default_version = 'v8.5'

function ConfigCenter() {
  const [listConfigParam, setListConfigParam] = useState<{
    cluster_type: CloudconfigClusterType
    param_name: string | undefined
    version: string
    configType: string
  }>({
    cluster_type: 'DEDICATED_TIDB',
    param_name: undefined,
    version: default_version,
    configType: 'tidb'
  })

  const [addConfig, setAddConfig] = useState(false)
  const [modifyConfig, setModifyConfig] = useState(false)
  const [copyConfig, setCopyConfig] = useState(false)
  const [toModify, setToModify] = useState<CloudconfigParameterAttribute>()
  const [versionOpts, setVersionOpts] = useState<string[]>()
  const [configTypeOpts, setConfigTypeOpts] = useState<string[]>()

  async function fetch() {
    try {
      const versions = (
        await cloudConfigControllerListParameterVersions({
          cluster_type: listConfigParam.cluster_type
        })
      ).data.versions
      const configTypes = (
        await cloudConfigControllerListConfigTypes(listConfigParam.cluster_type)
      ).data.config_types
      setVersionOpts(versions)
      setConfigTypeOpts(configTypes)
    } catch (e) {
      console.error(e)
    }
  }

  useEffect(() => {
    fetch()
  }, [listConfigParam.cluster_type])

  const getData = (params?: Partial<PageInfo>) => {
    return cloudConfigControllerListParameterAttributes(
      listConfigParam.configType,
      listConfigParam.version,
      {
        cluster_type: listConfigParam.cluster_type,
        name_like: listConfigParam.param_name,
        page: params?.page,
        per_page: params?.pageSize
      }
    )
  }

  const { dataSource, loading, reload, paginationProps, onTableChange } =
    useTable<ListData<CloudconfigParameterAttribute>>(getData, [], {
      pagination: true
    })

  const columns: ColumnsType<CloudconfigParameterAttribute> = [
    {
      title: 'Version',
      render: (_: any, record) => {
        return record.version
      }
    },
    {
      title: 'Config Name',
      render: (_: any, record) => {
        return <ConfigName value={record.name} />
      }
    },
    {
      title: 'Type',
      render: (_: any, record) => {
        return record.type
      }
    },
    {
      title: 'Default Value',
      render: (_: any, record) => {
        return <CodeValue value={record.default_value} />
      }
    },
    {
      title: 'Description',
      render: (_: any, record) => {
        return record.description
      }
    },
    {
      title: 'Validation',
      render: (_: any, record) => {
        return convertToString(record.validation)
      }
    },
    {
      title: 'Risk Level',
      render: (_: any, record) => {
        return record.risk_level
      }
    },
    {
      title: 'HotReloadable',
      render: (_: any, record) => {
        return record.apply_policy === null
          ? 'null'
          : record.apply_policy === CloudconfigParameterApplyPolicy.HotReload
          ? 'true'
          : 'false'
      }
    },
    {
      title: 'Action',
      render: (_: any, record) => {
        return (
          <Button
            type="primary"
            onClick={() => {
              setToModify(record)
              setModifyConfig(true)
            }}
          >
            Edit
          </Button>
        )
      }
    }
  ]

  const actions = useMemo(
    () => [
      <Select
        style={{ width: 140 }}
        options={[
          { label: 'Dedicated', value: 'DEDICATED_TIDB' },
          { label: 'TiCDC', value: 'TICDC' },
          { label: 'Changefeed', value: 'CHANGEFEED' },
          { label: 'Resource Pool', value: 'SHARED_POOL' },
          { label: 'Premium & BYOC', value: 'LOGICAL_CLUSTER' },
          { label: 'TiCDC NG', value: 'TICDC_NG' },
          { label: 'Changefeed NG', value: 'CHANGEFEED_NG' }
        ]}
        value={listConfigParam.cluster_type}
        onChange={(event) =>
          setListConfigParam((pre) => ({ ...pre, cluster_type: event }))
        }
      ></Select>,
      <Select
        style={{ width: 100 }}
        options={versionOpts?.map((v) => {
          return { label: v, value: v }
        })}
        value={listConfigParam.version}
        onChange={(event) =>
          setListConfigParam((pre) => ({ ...pre, version: event }))
        }
        placeholder="version like v6.5.0"
      ></Select>,
      <Select
        style={{ width: 180 }}
        options={configTypeOpts?.map((v) => {
          return { label: v, value: v }
        })}
        value={listConfigParam.configType}
        onChange={(event) => {
          setListConfigParam((pre) => ({
            ...pre,
            configType: event
          }))
        }}
        placeholder="config type"
      ></Select>,
      <Input
        value={listConfigParam.param_name}
        onChange={(event) =>
          setListConfigParam((pre) => ({
            ...pre,
            param_name: event.target.value
          }))
        }
        placeholder="param name"
      ></Input>,
      <Button
        type="primary"
        onClick={() => {
          if (!(listConfigParam.param_name || listConfigParam.version)) {
            Modal.error({
              title: 'Invalid Request',
              content:
                'At least one query option(version or param name) is required'
            })
          } else {
            reload()
          }
        }}
      >
        Search
      </Button>,
      <Button
        type="primary"
        onClick={() => {
          setAddConfig(true)
        }}
      >
        Add Config
      </Button> /*,
      <Button
        type="primary"
        onClick={() => {
          setCopyConfig(true)
        }}
      >
        Copy From Old Version
      </Button>*/
    ],
    [listConfigParam, versionOpts, configTypeOpts]
  )

  const renderAddFormFields = useCallback(
    (form: FormInstance) => {
      return (
        <AddConfigForm
          form={form}
          defaultClusterType={listConfigParam.cluster_type}
        />
      )
    },
    [addConfig, listConfigParam.cluster_type]
  )

  const handleAdd = useCallback(
    async (payload: AddConfigFormType) => {
      const req = {
        version: payload.version,
        name: payload.param_name,
        apply_policy: payload.apply_policy,
        cluster_type: payload.clusterType,
        config_type: payload.configType,
        default_value: parseFormValue(payload.type, payload.defaultVal),
        type: payload.type,
        description: payload.description,
        validation: payload.validation
      }
      try {
        await cloudConfigControllerCreateParameterAttribute({ attribute: req })
        Modal.success({
          title: 'Info',
          content: (
            <div>
              <p>Config has been added</p>
            </div>
          ),
          onOk() {}
        })
        setAddConfig(false)
        reload()
      } catch (error) {
        Modal.error({
          title: error.response.data.errcode,
          content: error.response.data.errmsg
        })
      }
    },
    [reload]
  )

  const handleCancelAdd = useCallback(() => {
    setAddConfig(false)
  }, [])

  const renderCopyFormFields = useCallback(
    (form: any) => {
      return <CopyConfigForm />
    },
    [copyConfig]
  )

  const handleCopy = useCallback(
    async (payload: ConfigcenterCopyFromVersionReq) => {
      try {
        await cloudConfigControllerCloneParameterAttribute({
          from_version: payload.from_version!,
          to_version: payload.to_version!
        })
        Modal.success({
          title: 'Info',
          content: (
            <div>
              <p>Config for version ${payload.to_version} has been added</p>
            </div>
          ),
          onOk() {}
        })
        setCopyConfig(false)
        reload()
      } catch (error) {
        Modal.error({
          title: error.response.data.errcode,
          content: error.response.data.errmsg
        })
      }
    },
    [reload]
  )

  const handleCancelCopy = useCallback(() => {
    setCopyConfig(false)
  }, [])

  const renderModifyFormFields = useCallback(
    (form: any) => {
      return <ModifyConfigForm form={form} />
    },
    [modifyConfig]
  )

  const handleModify = useCallback(
    async (payload: ModifyConfigFormType) => {
      const req = {
        apply_policy: payload.apply_policy,
        default_value: parseFormValue(payload.type, payload.default_value),
        validation: payload.validation,
        risk_level: payload.risk_level
      }
      try {
        await cloudConfigControllerUpdateParameterAttribute(
          payload.configType,
          payload.version,
          payload.param_name,
          req,
          {
            cluster_type: payload.cluster_type
          }
        )
        Modal.success({
          title: 'Info',
          content: (
            <div>
              <p>Config has been modified</p>
            </div>
          ),
          onOk() {}
        })
        setModifyConfig(false)
        reload()
      } catch (error) {
        Modal.error({
          title: error.response.data.errcode,
          content: error.response.data.errmsg
        })
      }
    },
    [reload]
  )

  const handleCancelModify = useCallback(() => {
    setModifyConfig(false)
  }, [])

  return (
    <div>
      <ListToolBar
        actions={actions}
        reload={() => {
          setListConfigParam({
            cluster_type: 'DEDICATED_TIDB',
            param_name: undefined,
            version: default_version,
            configType: 'tidb'
          })
          return reload()
        }}
      ></ListToolBar>
      <Table<CloudconfigParameterAttribute>
        rowKey="id"
        columns={columns}
        dataSource={dataSource}
        loading={loading}
        pagination={paginationProps}
        size="small"
        onChange={onTableChange}
      ></Table>
      <ModalForm<AddConfigFormType>
        visible={!!addConfig}
        name="addConfig"
        title={'Add a Config'}
        getFields={renderAddFormFields}
        onSubmit={handleAdd}
        onCancel={handleCancelAdd}
        width={1000}
      />
      <ModalForm<ConfigcenterCopyFromVersionReq>
        visible={!!copyConfig}
        name="copyConfig"
        title={'Copy Config From Some Version'}
        getFields={renderCopyFormFields}
        onSubmit={handleCopy}
        onCancel={handleCancelCopy}
        width={1000}
      />
      <ModalForm<ModifyConfigFormType>
        visible={!!modifyConfig}
        name="modifyConfig"
        title={'Modify Config'}
        getFields={renderModifyFormFields}
        onSubmit={handleModify}
        onCancel={handleCancelModify}
        width={1000}
        initValues={{
          cluster_type: toModify?.cluster_type || 'DEDICATED_TIDB',
          configType: toModify?.config_type || '',
          apply_policy:
            toModify?.apply_policy || CloudconfigParameterApplyPolicy.HotReload,
          version: toModify?.version || '',
          param_name: toModify?.name || ``,
          type: toModify?.type || ``,
          default_value: convertToString(toModify?.default_value),
          validation: convertToString(toModify?.validation),
          risk_level: toModify?.risk_level || 'low'
        }}
      />
    </div>
  )
}

export const version_to_string = (version: number | undefined) => {
  if (version) {
    const major = Math.floor(version / 1000000)
    const minor = Math.floor((version % 1000000) / 1000)
    const patch = version % 1000
    return `v${major}.${minor}.${patch}`
  }
  return ``
}

export const version_to_int = (version: string) => {
  const parsed = semver.parse(version)
  if (parsed) {
    return parsed.major * 1000000 + parsed.minor * 1000 + parsed.patch
  }
  return undefined
}

export default ConfigCenter
