import { Button, Collapse, Form, Input, Modal, Select, message } from 'antd'
import { FormInstance } from 'antd/es/form/Form'
import { useState } from 'react'

import { deploymentControllerCreateDeployment } from 'apiClient/services/deployment'
import { CreateDeploymentReqScenario } from 'apiClient/services/deployment/interface'

const { Option } = Select
const { TextArea } = Input
const { Panel } = Collapse

interface ParamDef {
  key: string
  label: string
  required: boolean
  placeholder?: string
  type?: 'input' | 'select' | 'json'
  options?: string[]
  helpText?: string
  dependencies?: string[]
  customValidator?: (form: FormInstance) => string | null
}

const jsonValidator = (_: any, value: string) => {
  if (!value || value === '') return Promise.resolve()
  try {
    const parsed = JSON.parse(value)
    if (
      typeof parsed !== 'object' ||
      parsed === null ||
      Array.isArray(parsed)
    ) {
      return Promise.reject(new Error('Must be a JSON object'))
    }
    return Promise.resolve()
  } catch {
    return Promise.reject(new Error('Must be valid JSON'))
  }
}

// Availability Zones XOR: exactly one of "availability-zones" (ids) and
// "availability-zone-names" (e.g. us-west-2a,us-west-2b) must be provided.
// Mirrors tidbcloud/devops PR #16 awsBYOCMapper.Validate.
const xorAvailabilityZones = (form: FormInstance): string | null => {
  const azIDs = form.getFieldValue('availability-zones')
  const azNames = form.getFieldValue('availability-zone-names')
  if (azIDs && azNames) {
    return 'Only one of Availability Zones (IDs) or Availability Zones (Names) may be provided'
  }
  return null
}

const requireOneAvailabilityZone = (form: FormInstance): string | null => {
  const azIDs = form.getFieldValue('availability-zones')
  const azNames = form.getFieldValue('availability-zone-names')
  if (!azIDs && !azNames) {
    return 'Either Availability Zones (IDs) or Availability Zones (Names) must be provided'
  }
  return null
}

// UI-only Scenario value for the Essential V2 tier. Maps internally to
// backend scenario=aws_premium_region with service-plan=EssentialV2.
// The backend awsPremiumMapper dispatches both with the same workflow
// (deploy-aws-premium-region.yml); only service-plan differs.
const ESSENTIAL_V2_KEY = 'aws_essential_v2_region'

// Availability-zone field keys that participate in the BYOC XOR pair.
// aws_premium_region has a single availability-zones field and does not
// participate in this grouping.
const AZ_PAIR_KEYS = ['availability-zones', 'availability-zone-names']
const isAzPairKey = (def: ParamDef) => AZ_PAIR_KEYS.includes(def.key)

const awsPremiumParams: ParamDef[] = [
  {
    key: 'environment',
    label: 'Environment',
    required: true,
    type: 'select',
    options: ['dev', 'staging', 'prod']
  },
  {
    key: 'region-name',
    label: 'Logical Region Name',
    required: true,
    placeholder: 'e.g. us-east-1-<postfix>'
  },
  {
    key: 'aws-region',
    label: 'AWS Region',
    required: true,
    placeholder: 'e.g. us-east-1'
  },
  {
    key: 'aws-account',
    label: 'Controlplane Account',
    required: true,
    placeholder: 'AWS account ID'
  },
  {
    key: 'dataplane-accounts',
    label: 'Dataplane Accounts',
    required: true,
    placeholder: 'Comma-separated account IDs'
  },
  {
    key: 'availability-zones',
    label: 'Availability Zones (IDs)',
    required: true,
    placeholder: 'e.g. use1-az1,use1-az2,use1-az3'
  },
  {
    key: 'eks',
    label: 'EKS',
    required: false,
    type: 'json',
    placeholder: `Example JSON object (see terraform/aws/premium/vars.tf):
{
  "k8s_version": "1.36",
  "node_groups": {
    "worker": {
      "name": "worker",
      "ami_type": "BOTTLEROCKET_x86_64",
      "instance_types": ["m6i.large"],
      "desired_size": 3,
      "min_size": 1,
      "max_size": 10
    }
  }
}`
  },
  {
    key: 'vpc',
    label: 'VPC',
    required: false,
    type: 'json',
    placeholder: `Example JSON object (see terraform/aws/premium/vars.tf):
{
  "cidr": "10.0.0.0/16"
}`
  },
  {
    key: 'target',
    label: 'Terraform Target',
    required: false,
    placeholder: 'Optional'
  }
]

const awsBYOCParams: ParamDef[] = [
  {
    key: 'environment',
    label: 'Environment',
    required: true,
    type: 'select',
    options: ['dev', 'staging', 'prod']
  },
  {
    key: 'region-name',
    label: 'Logical Region Name',
    required: true,
    placeholder: 'e.g. us-east-1-<postfix>'
  },
  {
    key: 'aws-region',
    label: 'AWS Region',
    required: true,
    placeholder: 'e.g. us-east-1'
  },
  {
    key: 'aws-account',
    label: 'Controlplane Account',
    required: true,
    placeholder: 'AWS account ID'
  },
  {
    key: 'dataplane-account',
    label: 'Dataplane Account',
    required: true,
    placeholder: 'Dataplane account ID'
  },
  {
    key: 'o11y-global-account',
    label: 'O11y Global Account',
    required: true,
    placeholder: 'Observability account ID'
  },
  {
    key: 'availability-zones',
    label: 'Availability Zones (IDs)',
    required: false,
    placeholder: 'e.g. use1-az1,use1-az2,use1-az3',
    helpText:
      'Provide either AZ IDs (this field) or AZ names (below), not both. The upstream workflow resolves names to IDs.',
    dependencies: ['availability-zone-names'],
    customValidator: xorAvailabilityZones
  },
  {
    key: 'availability-zone-names',
    label: 'Availability Zones (Names)',
    required: false,
    placeholder: 'e.g. us-east-1a,us-east-1b,us-east-1c',
    helpText:
      'Human-readable AZ names like us-west-2a,us-west-2b. Provide either AZ IDs (above) or AZ names, not both.',
    dependencies: ['availability-zones'],
    customValidator: (form) =>
      xorAvailabilityZones(form) || requireOneAvailabilityZone(form)
  },
  {
    key: 'byoc-tenant-id',
    label: 'BYOC Tenant ID',
    required: true,
    placeholder: 'Tenant ID'
  },
  {
    key: 'byoc-ecr',
    label: 'BYOC ECR',
    required: true,
    placeholder: 'ECR repository'
  },
  {
    key: 'seed-eks',
    label: 'Seed EKS',
    required: false,
    type: 'json',
    placeholder: `Example JSON object (see terraform/aws/byoc/seed/vars.tf):
{
  "k8s_version": "1.36",
  "node_groups": {
    "worker": {
      "name": "worker",
      "ami_type": "BOTTLEROCKET_x86_64",
      "instance_types": ["m6i.large"],
      "desired_size": 3,
      "min_size": 1,
      "max_size": 10
    }
  }
}`
  },
  {
    key: 'shoot-eks',
    label: 'Shoot EKS',
    required: false,
    type: 'json',
    placeholder: `Example JSON object (see terraform/aws/byoc/shoot/vars.tf):
{
  "k8s_version": "1.36",
  "node_groups": {
    "worker": {
      "name": "worker",
      "labels": { "node_type": "worker" }
    }
  },
  "node_group_az": "us-east-1a"
}`
  },
  {
    key: 'seed-vpc',
    label: 'Seed VPC',
    required: false,
    type: 'json',
    placeholder: `Example JSON object (see terraform/aws/byoc/seed/vars.tf):
{
  "cidr": "10.0.0.0/16"
}`
  },
  {
    key: 'shoot-vpc',
    label: 'Shoot VPC',
    required: false,
    type: 'json',
    placeholder: `Example JSON object (see terraform/aws/byoc/shoot/vars.tf):
{
  "cidr": "10.0.0.0/16",
  "enable_ecr_privatelink": true
}`
  },
  {
    key: 'cloudformation-region',
    label: 'CloudFormation Region',
    required: false,
    placeholder: 'Optional'
  },
  {
    key: 'tidb-hosted-zone-id',
    label: 'TiDB Hosted Zone ID',
    required: false,
    placeholder: 'Optional'
  },
  {
    key: 'o11y-hosted-zone-id',
    label: 'O11y Hosted Zone ID',
    required: false,
    placeholder: 'Optional'
  },
  {
    key: 'pca-arn',
    label: 'PCA ARN',
    required: false,
    placeholder: 'Optional'
  },
  {
    key: 'target',
    label: 'Terraform Target',
    required: false,
    placeholder: 'Optional'
  }
]

const scenarioParams: Record<string, ParamDef[]> = {
  aws_premium_region: awsPremiumParams,
  aws_byoc_region: awsBYOCParams,
  [ESSENTIAL_V2_KEY]: awsPremiumParams
}

function renderField(def: ParamDef) {
  if (def.type === 'select' && def.options) {
    return (
      <Select placeholder={def.placeholder}>
        {def.options.map((opt) => (
          <Option key={opt} value={opt}>
            {opt}
          </Option>
        ))}
      </Select>
    )
  }
  if (def.type === 'json') {
    return <TextArea rows={3} placeholder={def.placeholder} />
  }
  return <Input placeholder={def.placeholder} />
}

function buildRules(def: ParamDef, form: FormInstance) {
  const rules: any[] = []
  if (def.required) {
    rules.push({ required: true, message: `${def.label} is required` })
  }
  if (def.type === 'json') {
    rules.push({ validator: jsonValidator })
  }
  if (def.customValidator) {
    const cf = def.customValidator
    rules.push({
      validator: (_: any, value: any) => {
        const result = cf(form)
        if (result) {
          return Promise.reject(new Error(result))
        }
        return Promise.resolve()
      }
    })
  }
  return rules.length > 0 ? rules : undefined
}

export default function CreateDeploymentForm({
  onSuccess
}: {
  onSuccess: () => void
}) {
  const [visible, setVisible] = useState(false)
  const [loading, setLoading] = useState(false)
  const [scenario, setScenario] = useState<string>('aws_premium_region')
  const [form] = Form.useForm()

  const handleOpen = () => {
    form.resetFields()
    setScenario('aws_premium_region')
    setVisible(true)
  }

  const handleSubmit = async () => {
    try {
      const values = await form.validateFields()
      setLoading(true)

      const params: Record<string, string> = {}
      const paramDefs = scenarioParams[values.scenario] || []
      for (const def of paramDefs) {
        const val = values[def.key]
        if (val !== undefined && val !== '') {
          params[def.key] = val
        }
      }

      // Translate the UI-only Essential V2 scenario into the backend
      // scenario + service-plan combination. All other scenarios map
      // 1:1 with service-plan=Premium.
      const isEssentialV2 = values.scenario === ESSENTIAL_V2_KEY
      const apiScenario = isEssentialV2
        ? ('aws_premium_region' as CreateDeploymentReqScenario)
        : (values.scenario as CreateDeploymentReqScenario)
      params['service-plan'] = isEssentialV2 ? 'EssentialV2' : 'Premium'

      await deploymentControllerCreateDeployment({
        scenario: apiScenario,
        params
      })

      message.success('Deployment created successfully')
      setVisible(false)
      onSuccess()
    } catch (error: any) {
      if (error?.response?.data) {
        Modal.error({
          title: error.response.data.errcode,
          content: error.response.data.errmsg
        })
      }
    } finally {
      setLoading(false)
    }
  }

  const currentParams = scenarioParams[scenario] || []
  const isAwsByoc = scenario === 'aws_byoc_region'
  // The BYOC scenario has an availability-zones XOR pair that the user
  // must fill in (exactly one of the two). Pull it out of the
  // required/optional buckets so it renders outside the Advanced
  // Parameters collapse and is not visually grouped with truly
  // optional fields.
  const azPairParams = isAwsByoc ? currentParams.filter(isAzPairKey) : []
  const requiredParams = currentParams.filter(
    (def) => def.required && !azPairParams.includes(def)
  )
  const otherOptionalParams = currentParams.filter(
    (def) => !def.required && !azPairParams.includes(def)
  )

  return (
    <>
      <Button type="primary" onClick={handleOpen}>
        Create Deployment
      </Button>
      <Modal
        title="Create Deployment"
        open={visible}
        onOk={handleSubmit}
        onCancel={() => setVisible(false)}
        confirmLoading={loading}
        width={640}
        destroyOnClose
      >
        <Form
          form={form}
          layout="vertical"
          initialValues={{ scenario: 'aws_premium_region' }}
        >
          <Form.Item
            name="scenario"
            label="Scenario"
            rules={[{ required: true }]}
          >
            <Select onChange={(val) => setScenario(val)}>
              <Option value="aws_premium_region">AWS Premium Region</Option>
              <Option value="aws_byoc_region">AWS BYOC Region</Option>
              <Option value="aws_essential_v2_region">
                AWS Essential V2 Region
              </Option>
            </Select>
          </Form.Item>
          {requiredParams.map((def) => (
            <Form.Item
              key={def.key}
              name={def.key}
              label={def.label}
              dependencies={def.dependencies}
              rules={buildRules(def, form)}
              extra={def.helpText}
            >
              {renderField(def)}
            </Form.Item>
          ))}
          {azPairParams.length > 0 && (
            <div style={{ marginTop: 8 }}>
              {azPairParams.map((def) => (
                <Form.Item
                  key={def.key}
                  name={def.key}
                  label={def.label}
                  dependencies={def.dependencies}
                  rules={buildRules(def, form)}
                  extra={def.helpText}
                >
                  {renderField(def)}
                </Form.Item>
              ))}
            </div>
          )}
          {otherOptionalParams.length > 0 && (
            <Collapse style={{ marginTop: 16 }}>
              <Panel header="Advanced Parameters" key="advanced">
                {otherOptionalParams.map((def) => (
                  <Form.Item
                    key={def.key}
                    name={def.key}
                    label={def.label}
                    dependencies={def.dependencies}
                    rules={buildRules(def, form)}
                    extra={def.helpText}
                  >
                    {renderField(def)}
                  </Form.Item>
                ))}
              </Panel>
            </Collapse>
          )}
        </Form>
      </Modal>
    </>
  )
}
