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

import {
  cloudConfigControllerListAvailableClusterVersions,
  cloudConfigControllerListInstanceTypes,
  cloudConfigControllerListTemplates,
  cloudConfigControllerUpdateTemplateDefaultCaseBindingByOp
} from 'apiClient/services/devops'
import {
  CloudConfigControllerListInstanceTypesParams,
  CloudconfigCloudInstanceType,
  CloudconfigClusterType,
  CloudconfigTemplate,
  CloudconfigTemplateType,
  CloudconfigUpdateTemplateDefaultCaseBindingByOpReq
} from 'apiClient/services/devops/interface'

export type ModifyTenantDefaultTemplateBindingFormType = {
  cluster_type: CloudconfigClusterType
  config_type: string
  cloud_provider_instance_type_format: string
  reason: string
  template_id: number | null
  tenant_id: string
  version: string
}

type ModifyTenantDefaultTemplateBindingFormErrors = Partial<
  Record<keyof ModifyTenantDefaultTemplateBindingFormType, string>
>

const getInitialFormValue = ({
  clusterType,
  tenantId
}: {
  clusterType: CloudconfigClusterType
  tenantId?: string
}): ModifyTenantDefaultTemplateBindingFormType => ({
  cluster_type: clusterType,
  cloud_provider_instance_type_format: '',
  config_type: '',
  reason: '',
  template_id: null,
  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 ModifyTenantDefaultTemplateBinding({
  org_id,
  cluster_type,
  onSuccess,
  onCancel
}: {
  org_id?: string
  cluster_type: CloudconfigClusterType
  onSuccess: () => void
  onCancel: () => void
}) {
  const [availableVersions, setAvailableVersions] = useState<string[]>([])
  const [availableInstanceTypes, setAvailableInstanceTypes] = useState<
    CloudconfigCloudInstanceType[]
  >([])
  const [availableTemplates, setAvailableTemplates] = useState<
    CloudconfigTemplate[]
  >([])
  const [submitting, setSubmitting] = useState(false)
  const [formErrors, setFormErrors] =
    useState<ModifyTenantDefaultTemplateBindingFormErrors>({})
  const [formValue, setFormValue] =
    useState<ModifyTenantDefaultTemplateBindingFormType>(() =>
      getInitialFormValue({
        clusterType: cluster_type,
        tenantId: org_id
      })
    )

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

  useEffect(() => {
    const fetchVersions = async () => {
      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])

  useEffect(() => {
    const fetchTemplates = async () => {
      try {
        const templates = (
          await cloudConfigControllerListTemplates({
            cluster_type: cluster_type,
            template_type: CloudconfigTemplateType.tenant_default,
            tenant_id: org_id
          })
        ).data.items
        setAvailableTemplates(templates || [])
      } catch (error) {
        notifier.error(getErrorContent(error), {
          title: 'Failed to fetch templates'
        })
      }
    }

    void fetchTemplates()
  }, [cluster_type, org_id])

  useEffect(() => {
    const fetchInstanceTypes = async () => {
      try {
        const params: CloudConfigControllerListInstanceTypesParams = {}
        const tuples = (
          await cloudConfigControllerListInstanceTypes(cluster_type, params)
        ).data
        setAvailableInstanceTypes(tuples.instance_types || [])
      } catch (error) {
        notifier.error(getErrorContent(error), {
          title: 'Failed to fetch instance types'
        })
      }
    }

    void fetchInstanceTypes()
  }, [cluster_type])

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

  const templateOptions = useMemo(
    () =>
      availableTemplates.map((template) => ({
        label: `${template.name} (${template.id})`,
        value: template.id?.toString() || ''
      })),
    [availableTemplates]
  )

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

  const instanceTypeOptions = useMemo(
    () =>
      availableInstanceTypes.map((value) => ({
        label: `[${value.cloud_provider}] ${value.instance_type}`,
        value: `${value.cloud_provider}/${value.instance_type}`
      })),
    [availableInstanceTypes]
  )

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

    if (!formValue.template_id) {
      nextErrors.template_id = 'Template is required'
    }
    if (!formValue.version) {
      nextErrors.version = 'Version is required'
    }
    if (!formValue.cloud_provider_instance_type_format) {
      nextErrors.cloud_provider_instance_type_format =
        'Instance type is required'
    }
    if (!formValue.reason.trim()) {
      nextErrors.reason = 'Reason is required'
    }

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

  const handleTemplateChange = useCallback(
    (value: string | null) => {
      const templateId = value ? Number(value) : null
      const targetTemplate = availableTemplates.find(
        (template) => template.id === templateId
      )

      setFormValue((prev) => ({
        ...prev,
        config_type: targetTemplate?.config_type || '',
        template_id: templateId
      }))
      setFormErrors((prev) => ({
        ...prev,
        config_type: undefined,
        template_id: undefined
      }))
    },
    [availableTemplates]
  )

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

    const template = availableTemplates.find(
      (item) => item.id === formValue.template_id
    )
    if (!template) {
      notifier.error('Selected template not found')
      return
    }

    const [cloudProvider, instanceType] =
      formValue.cloud_provider_instance_type_format.split('/')
    const req: CloudconfigUpdateTemplateDefaultCaseBindingByOpReq = {
      default_case_bindings: {
        cluster_type: cluster_type,
        default_case: {
          cloud_provider: cloudProvider,
          config_type: template?.config_type,
          instance_type: instanceType,
          tenant_id: org_id,
          version: formValue.version
        },
        template_id: formValue.template_id!
      },
      reason: formValue.reason.trim()
    }

    setSubmitting(true)
    try {
      const resp = (
        await cloudConfigControllerUpdateTemplateDefaultCaseBindingByOp(req)
      ).data
      notifier.success(
        'Modify template binding request submitted successfully',
        {
          title: 'Modify Tenant Default Template Binding'
        }
      )
      onSuccess()
      window.open(`/operations/${resp.instance_id}`, '_blank')
    } catch (error) {
      notifier.error(getErrorContent(error), {
        title: 'Failed to modify template binding'
      })
    } finally {
      setSubmitting(false)
    }
  }, [
    availableTemplates,
    cluster_type,
    formValue,
    org_id,
    onSuccess,
    validateForm
  ])

  return (
    <Stack gap="md">
      <TextInput disabled label="Cluster Type" value={formValue.cluster_type} />
      <TextInput disabled label="Tenant ID" value={formValue.tenant_id} />
      <Select
        data={templateOptions}
        error={formErrors.template_id}
        label="Template"
        required
        searchable
        value={formValue.template_id ? formValue.template_id.toString() : null}
        onChange={handleTemplateChange}
      />
      <TextInput disabled label="Config Type" value={formValue.config_type} />
      <Select
        data={versionOptions}
        error={formErrors.version}
        label="Version"
        required
        searchable
        value={formValue.version || null}
        onChange={(value) => setFieldValue('version', value || '')}
      />
      <Select
        data={instanceTypeOptions}
        error={formErrors.cloud_provider_instance_type_format}
        label="Instance Type"
        required
        searchable
        value={formValue.cloud_provider_instance_type_format || null}
        onChange={(value) =>
          setFieldValue('cloud_provider_instance_type_format', value || '')
        }
      />
      <Textarea
        error={formErrors.reason}
        label="Reason"
        minRows={4}
        required
        value={formValue.reason}
        onChange={(event) => setFieldValue('reason', event.currentTarget.value)}
      />

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