import {
  Alert,
  Button,
  Card,
  Group,
  Select,
  Stack,
  TextInput,
  Typography,
  notifier
} from '@tidbcloud/uikit'
import { useCallback, useEffect, useMemo, useState } from 'react'

import {
  cloudConfigControllerCreateConfigurationTemplateChange,
  cloudConfigControllerListAvailableClusterVersions,
  cloudConfigControllerListConfigTypes,
  cloudConfigControllerListTemplateDefaultCaseBindings
} from 'apiClient/services/devops'
import {
  CloudConfigControllerListTemplateDefaultCaseBindingsClusterType,
  CloudconfigClusterType,
  CloudconfigCreateConfigurationTemplateChangeReq,
  CloudconfigParameterApplyPolicy,
  CloudconfigTemplateType
} from 'apiClient/services/devops/interface'
import ParameterManager, {
  ParameterValue
} from 'pages/ConfigCenter/Template/components/ParameterManager'
import { isValidConfigIdentifier } from 'utils/string'

export type CreateTenantDefaultTemplateFormType = {
  template_name: string
  cluster_type: CloudconfigClusterType
  config_type: string
  tenant_id: string
  version: string
}

type CreateTenantDefaultTemplateFormErrors = Partial<
  Record<keyof CreateTenantDefaultTemplateFormType, string>
>

const getInitialFormValue = ({
  clusterType,
  tenantId
}: {
  clusterType: CloudconfigClusterType
  tenantId?: string
}): CreateTenantDefaultTemplateFormType => ({
  cluster_type: clusterType,
  config_type: '',
  template_name: '',
  tenant_id: tenantId || '',
  version: ''
})

const getErrorContent = (error: any) =>
  error?.response?.data?.errmsg ||
  error?.response?.data?.message ||
  error?.response?.data?.error ||
  error?.message ||
  String(error)

export default function CreateTenantDefaultTemplateForm({
  org_id,
  cluster_type,
  onSuccess,
  onCancel
}: {
  org_id?: string
  cluster_type: CloudconfigClusterType
  onSuccess: () => void
  onCancel: () => void
}) {
  const isSharedPool = cluster_type === CloudconfigClusterType.SHARED_POOL
  const [availableVersions, setAvailableVersions] = useState<string[]>([])
  const [loadingVersions, setLoadingVersions] = useState(false)
  const [availableConfigTypes, setAvailableConfigTypes] = useState<string[]>([])
  const [submitting, setSubmitting] = useState(false)
  const [formErrors, setFormErrors] =
    useState<CreateTenantDefaultTemplateFormErrors>({})
  const [formValue, setFormValue] =
    useState<CreateTenantDefaultTemplateFormType>(() =>
      getInitialFormValue({
        clusterType: cluster_type,
        tenantId: org_id
      })
    )
  const [parameters, setParameters] = useState<Record<string, ParameterValue>>(
    {}
  )

  useEffect(() => {
    setFormValue(
      getInitialFormValue({
        clusterType: cluster_type,
        tenantId: org_id
      })
    )
    setFormErrors({})
    setParameters({})
  }, [cluster_type, org_id])

  useEffect(() => {
    const fetchVersions = async () => {
      if (isSharedPool) {
        setAvailableVersions([])
        setLoadingVersions(false)
        setFormValue((prev) => ({ ...prev, version: '' }))
        return
      }

      try {
        const versions = (
          await cloudConfigControllerListAvailableClusterVersions(cluster_type)
        ).data.items

        setAvailableVersions(versions ? versions?.map((v) => v.version!) : [])
      } catch (error) {
        notifier.error(getErrorContent(error), {
          title: 'Failed to fetch versions'
        })
      }
    }

    void fetchVersions()
  }, [cluster_type, isSharedPool])

  useEffect(() => {
    if (!isSharedPool) {
      setLoadingVersions(false)
      return
    }

    if (!formValue.config_type) {
      setAvailableVersions([])
      setLoadingVersions(false)
      setFormValue((prev) => ({ ...prev, version: '' }))
      return
    }

    let mounted = true

    const fetchSharedPoolVersions = async () => {
      setLoadingVersions(true)
      try {
        const bindings = (
          await cloudConfigControllerListTemplateDefaultCaseBindings({
            cluster_type:
              CloudConfigControllerListTemplateDefaultCaseBindingsClusterType.SHARED_POOL,
            config_type_is: formValue.config_type,
            per_page: 1000
          })
        ).data.items

        if (!mounted) {
          return
        }

        const versions = Array.from(
          new Set(
            (bindings || [])
              .map((binding) => binding.default_case?.version)
              .filter(Boolean) as string[]
          )
        )

        setAvailableVersions(versions)
      } catch (error) {
        notifier.error(getErrorContent(error), {
          title: 'Failed to fetch shared pool versions'
        })
      } finally {
        if (mounted) {
          setLoadingVersions(false)
        }
      }
    }

    void fetchSharedPoolVersions()

    return () => {
      mounted = false
    }
  }, [formValue.config_type, isSharedPool])

  useEffect(() => {
    const fetchConfigTypes = async () => {
      try {
        const configTypes = (
          await cloudConfigControllerListConfigTypes(cluster_type)
        ).data.config_types
        setAvailableConfigTypes(configTypes || [])
      } catch (error) {
        notifier.error(getErrorContent(error), {
          title: 'Failed to fetch config types'
        })
      }
    }

    void fetchConfigTypes()
  }, [cluster_type])

  const versionOptions = useMemo(
    () => availableVersions.map((value) => ({ label: value, value })),
    [availableVersions]
  )

  const configTypeOptions = useMemo(
    () => availableConfigTypes.map((value) => ({ label: value, value })),
    [availableConfigTypes]
  )

  const setFieldValue = useCallback(
    <K extends keyof CreateTenantDefaultTemplateFormType>(
      field: K,
      value: CreateTenantDefaultTemplateFormType[K]
    ) => {
      setFormValue((prev) => ({ ...prev, [field]: value }))
      setFormErrors((prev) => ({ ...prev, [field]: undefined }))
    },
    []
  )

  const handleConfigTypeChange = useCallback((value: string | null) => {
    setFormValue((prev) => ({
      ...prev,
      config_type: value || '',
      version: ''
    }))
    setFormErrors((prev) => ({
      ...prev,
      config_type: undefined,
      version: undefined
    }))
    setAvailableVersions([])
    setParameters({})
  }, [])

  const handleParamChange = (name: string, value: ParameterValue) => {
    setParameters((prev) => ({
      ...prev,
      [name]: value
    }))
  }

  const handleParameterRemove = (name: string) => {
    setParameters((prev) => {
      const newParams = { ...prev }
      delete newParams[name]
      return newParams
    })
  }

  const validateForm = useCallback(() => {
    const nextErrors: CreateTenantDefaultTemplateFormErrors = {}

    if (!formValue.template_name.trim()) {
      nextErrors.template_name = 'Template name is required'
    }
    if (!formValue.config_type) {
      nextErrors.config_type = 'Config type is required'
    } else if (!isValidConfigIdentifier(formValue.config_type)) {
      nextErrors.config_type =
        'Only letters, numbers, underscores, hyphens, and dots are allowed'
    }
    if (!formValue.version) {
      nextErrors.version = 'Version is required'
    }

    setFormErrors(nextErrors)
    return Object.keys(nextErrors).length === 0
  }, [formValue])

  const handleCancel = useCallback(() => {
    setParameters({})
    setFormErrors({})
    onCancel()
  }, [onCancel])

  const handleSubmit = useCallback(async () => {
    if (!validateForm()) {
      notifier.error('Please fix the highlighted fields before continuing.')
      return
    }

    const req: CloudconfigCreateConfigurationTemplateChangeReq = {
      apply_policy: CloudconfigParameterApplyPolicy.RollingRestart,
      change_type:
        cluster_type === CloudconfigClusterType.DEDICATED_TIDB
          ? 'fulltidb'
          : cluster_type === CloudconfigClusterType.SHARED_POOL
          ? 'sharedpool'
          : 'undefined',
      cluster_type: cluster_type,
      files: [
        {
          config_type: formValue.config_type,
          custom_parameters: Object.entries(parameters).map(([key, val]) => ({
            name: key,
            value: val.value
          })),
          filename: formValue.config_type
        }
      ],
      reason: formValue.template_name.trim(),
      template_type: CloudconfigTemplateType.tenant_default,
      tenant_id: org_id,
      version: {
        to_version: formValue.version
      }
    }

    setSubmitting(true)
    try {
      const resp = await cloudConfigControllerCreateConfigurationTemplateChange(
        req
      )
      notifier.success('Template create request submitted successfully', {
        title: 'Create Tenant Default Template'
      })
      onSuccess()
      window.open(`/confighistories/${resp.data.change_id}`, '_blank')
    } catch (error) {
      notifier.error(getErrorContent(error), {
        title: 'Failed to create tenant default template'
      })
    } finally {
      setSubmitting(false)
    }
  }, [cluster_type, formValue, org_id, onSuccess, parameters, validateForm])

  return (
    <Stack gap="lg">
      <Stack gap="md">
        <TextInput
          disabled
          label="Cluster Type"
          value={formValue.cluster_type}
        />
        <TextInput disabled label="Tenant ID" value={formValue.tenant_id} />
        <TextInput
          error={formErrors.template_name}
          label="Template Name"
          placeholder="Enter template name"
          required
          value={formValue.template_name}
          onChange={(event) =>
            setFieldValue('template_name', event.currentTarget.value)
          }
        />

        {isSharedPool ? (
          <>
            <Select
              data={configTypeOptions}
              error={formErrors.config_type}
              label="Config Type"
              required
              searchable
              value={formValue.config_type || null}
              onChange={handleConfigTypeChange}
            />
            <Select
              data={versionOptions}
              disabled={!formValue.config_type || loadingVersions}
              error={formErrors.version}
              label="Version"
              placeholder={
                loadingVersions
                  ? 'Loading versions...'
                  : formValue.config_type
                  ? 'Select version'
                  : 'Please select config type first'
              }
              required
              searchable
              value={formValue.version || null}
              onChange={(value) => setFieldValue('version', value || '')}
            />
          </>
        ) : (
          <>
            <Select
              data={versionOptions}
              error={formErrors.version}
              label="Version"
              required
              searchable
              value={formValue.version || null}
              onChange={(value) => setFieldValue('version', value || '')}
            />
            <Select
              data={configTypeOptions}
              error={formErrors.config_type}
              label="Config Type"
              required
              searchable
              value={formValue.config_type || null}
              onChange={(value) => {
                setFieldValue('config_type', value || '')
                setParameters({})
              }}
            />
          </>
        )}
      </Stack>

      <Card withBorder shadow="xs" padding="md" radius="sm">
        <Stack gap="md">
          <Typography variant="title-md">Configuration Parameters</Typography>
          {formValue.version && (!isSharedPool || formValue.config_type) ? (
            <ParameterManager
              configType={formValue.config_type}
              clusterType={cluster_type}
              version={formValue.version}
              selectedParams={parameters}
              onParameterChange={handleParamChange}
              onParameterRemove={handleParameterRemove}
            />
          ) : (
            <Alert color="blue" variant="light">
              Please select version and config type first.
            </Alert>
          )}
        </Stack>
      </Card>

      <Group justify="flex-end" gap="sm">
        <Button disabled={submitting} onClick={handleCancel} variant="default">
          Cancel
        </Button>
        <Button loading={submitting} onClick={handleSubmit}>
          Create
        </Button>
      </Group>
    </Stack>
  )
}
