"use client";

import type { ServerConnectorType, ServerGroup } from "@domainops/shared-types";
import { Alert, App, Button, Collapse, Form, Input, InputNumber, Modal, Radio, Select, Upload } from "antd";
import {
  ApiOutlined,
  CloudServerOutlined,
  ControlOutlined,
  DatabaseOutlined,
  KeyOutlined,
  LockOutlined,
  SearchOutlined,
  UploadOutlined,
} from "@ant-design/icons";
import type { ReactNode } from "react";
import { useEffect, useState } from "react";
import { createServerGroup, locateHuaweiServer, updateServerGroup } from "@/lib/api/servers";
import type { LocateHuaweiResult } from "@/lib/api/servers";
import { CopyIpButton, useAppIp } from "./AppIpHint";
import { reportFormErrors } from "@/lib/utils/formErrors";
import type { CreateServerGroupInput } from "@/lib/api/servers";

const CLASSIFICATION_OPTIONS = [
  { value: "shared", label: "Shared" },
  { value: "vps", label: "VPS" },
  { value: "dedicated", label: "Dedicated" },
  { value: "reseller", label: "Reseller" },
];

interface ConnectorOption {
  value: ServerConnectorType;
  title: string;
  hint: string;
  icon: ReactNode;
}

const CONNECTOR_OPTIONS: ConnectorOption[] = [
  { value: "cpanel", title: "cPanel / WHM", hint: "Shared, reseller or VPS with WHM", icon: <ControlOutlined /> },
  { value: "aws", title: "AWS", hint: "EC2 over SSH, plus the AWS API", icon: <CloudServerOutlined /> },
  { value: "huawei", title: "Huawei Cloud ECS", hint: "ECS over SSH, plus the Huawei API", icon: <CloudServerOutlined /> },
  { value: "btpanel", title: "BT Panel", hint: "Sites and files through the panel API", icon: <ApiOutlined /> },
  { value: "huawei_bt", title: "Huawei ECS + BT Panel", hint: "One server: the Huawei API and the BT Panel API", icon: <CloudServerOutlined /> },
];

type FieldKey = keyof CreateServerGroupInput;

const SSH_FIELDS: FieldKey[] = ["auth_method", "ssh_username", "ssh_port", "ssh_key", "ssh_password"];
const CLOUD_FIELDS: FieldKey[] = [
  "web_root_base",
  "aws_region",
  "aws_instance_id",
  "aws_security_group_id",
  "aws_access_key_id",
  "aws_secret_access_key",
  "db_admin_username",
  "db_admin_password",
];

/**
 * The fields each connector type actually uses - anything else is dropped
 * from the request, so switching the type never sends values left behind in
 * fields that are no longer on screen.
 */
const FIELDS_BY_TYPE: Record<ServerConnectorType, FieldKey[]> = {
  cpanel: ["ip_address", "url", "whm_host", "whm_username", "whm_api_token", ...SSH_FIELDS],
  aws: ["ip_address", "url", ...CLOUD_FIELDS, ...SSH_FIELDS],
  huawei: ["ip_address", ...CLOUD_FIELDS, "huawei_project_id", ...SSH_FIELDS],
  btpanel: ["ip_address", "url", "bt_api_key"],
  huawei_bt: [
    "ip_address",
    "url",
    "bt_api_key",
    "aws_region",
    "aws_instance_id",
    "aws_security_group_id",
    "aws_access_key_id",
    "aws_secret_access_key",
    "huawei_project_id",
  ],
};

const COMMON_FIELDS: FieldKey[] = [
  "label",
  "connector_type",
  "hosting_classification",
  "provider",
  "location",
  "capacity_static",
  "capacity_wp",
];

function ConnectorCards({
  value,
  onChange,
  isLocked = false,
}: {
  value?: ServerConnectorType;
  onChange?: (value: ServerConnectorType) => void;
  isLocked?: boolean;
}) {
  const options = isLocked ? CONNECTOR_OPTIONS.filter((option) => option.value === value) : CONNECTOR_OPTIONS;

  return (
    <div className="grid grid-cols-1 sm:grid-cols-2 gap-3 dms_server_type_cards" role="radiogroup" aria-label="Connector Type">
      {options.map((option) => (
        <button
          key={option.value}
          type="button"
          role="radio"
          aria-checked={value === option.value}
          onClick={() => onChange?.(option.value)}
          disabled={isLocked}
          className={`dms_server_type_card${value === option.value ? " is-selected" : ""}`}
        >
          <span className="dms_server_type_card_icon">{option.icon}</span>
          <span className="flex flex-col text-left min-w-0">
            <span className="dms_server_type_card_title">{option.title}</span>
            <span className="dms_server_type_card_hint">{option.hint}</span>
          </span>
        </button>
      ))}
    </div>
  );
}

function Section({ icon, title, hint, children, className }: { icon: ReactNode; title: string; hint?: string; children: ReactNode; className?: string }) {
  return (
    <section className={`dms_server_section ${className ?? ""}`}>
      <header className="dms_server_section_head">
        <span className="dms_server_section_icon">{icon}</span>
        <span className="flex flex-col">
          <span className="dms_server_section_title">{title}</span>
          {hint && <span className="dms_server_section_hint">{hint}</span>}
        </span>
      </header>
      {children}
    </section>
  );
}

export function ServerGroupFormModal({
  open,
  group,
  onClose,
  onSaved,
}: {
  open: boolean;
  group: ServerGroup | null;
  onClose: () => void;
  onSaved: () => void;
}) {
  const { message } = App.useApp();
  const [form] = Form.useForm<CreateServerGroupInput>();
  const [isSubmitting, setIsSubmitting] = useState(false);
  const authMethod = Form.useWatch("auth_method", form);
  const watchedType = Form.useWatch("connector_type", form);
  const connectorType: ServerConnectorType = watchedType ?? group?.connector_type ?? "cpanel";
  const isEditing = !!group;
  const isAws = connectorType === "aws";
  const isHuawei = connectorType === "huawei" || connectorType === "huawei_bt";
  const isBt = connectorType === "btpanel";
  const hasBtPanel = connectorType === "btpanel" || connectorType === "huawei_bt";
  const usesSsh = connectorType === "cpanel" || connectorType === "aws" || connectorType === "huawei";
  const isCpanel = connectorType === "cpanel";
  const isCloud = isAws || isHuawei;
  const appIp = useAppIp(open);
  const [locateResult, setLocateResult] = useState<LocateHuaweiResult | null>(null);
  const [isLocating, setIsLocating] = useState(false);
  const keepNote = isEditing ? "Leave blank to keep the current value." : undefined;

  useEffect(() => {
    if (!open) return;
    form.resetFields();
    if (group) {
      form.setFieldsValue({
        label: group.label,
        provider: group.provider ?? undefined,
        location: group.location ?? undefined,
        hosting_classification: group.hosting_classification,
        connector_type: group.connector_type,
        whm_host: group.whm_host ?? undefined,
        ip_address: group.ip_address ?? undefined,
        url: group.url ?? undefined,
        auth_method: group.auth_method,
        whm_username: group.whm_username ?? undefined,
        ssh_username: group.ssh_username ?? undefined,
        ssh_port: group.ssh_port,
        web_root_base: group.web_root_base ?? undefined,
        aws_region: group.aws_region ?? undefined,
        aws_instance_id: group.aws_instance_id ?? undefined,
        aws_security_group_id: group.aws_security_group_id ?? undefined,
        huawei_project_id: group.huawei_project_id ?? undefined,
        db_admin_username: group.db_admin_username ?? undefined,
        capacity_static: group.capacity_static ?? undefined,
        capacity_wp: group.capacity_wp ?? undefined,
      });
    }
  }, [open, group, form]);

  useEffect(() => {
    if (connectorType !== "cpanel" && form.getFieldValue("auth_method") === "api") form.setFieldValue("auth_method", "ssh");
  }, [connectorType, form]);

  async function handleLocate() {
    const values = form.getFieldsValue();

    if (!values.ip_address) {
      message.warning("Enter the server's IP address first - it is what the server is looked up by.");

      return;
    }

    setIsLocating(true);
    try {
      setLocateResult(
        await locateHuaweiServer({
          ip_address: values.ip_address,
          aws_access_key_id: values.aws_access_key_id || undefined,
          aws_secret_access_key: values.aws_secret_access_key || undefined,
          server_group_id: group?.id,
        }),
      );
    } catch (err) {
      message.error(reportFormErrors(form, err, "Couldn't search the Huawei account."));
    } finally {
      setIsLocating(false);
    }
  }

  function applyLocated(match: { region: string; project_id: string; server_id: string }) {
    form.setFieldsValue({ aws_region: match.region, huawei_project_id: match.project_id, aws_instance_id: match.server_id });
    message.success("Region, project ID and server ID filled in.");
  }

  async function handleSubmit(values: CreateServerGroupInput) {
    const allowed = new Set<FieldKey>([...COMMON_FIELDS, ...FIELDS_BY_TYPE[connectorType]]);
    if (isEditing) allowed.delete("connector_type");
    const payload = Object.fromEntries(Object.entries(values).filter(([key]) => allowed.has(key as FieldKey))) as CreateServerGroupInput;

    setIsSubmitting(true);
    try {
      if (group) {
        await updateServerGroup(group.id, payload);
        message.success(`${values.label} updated.`);
      } else {
        await createServerGroup(payload);
        message.success(`${values.label} added.`);
      }
      onSaved();
    } catch (err) {
      message.error(reportFormErrors(form, err, "Couldn't save that server group."));
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    <Modal
      title={
        <span className="flex items-center gap-2">
          <CloudServerOutlined />
          {isEditing ? `Edit Server Group - ${group?.label}` : "Add Server Group"}
        </span>
      }
      open={open}
      onCancel={onClose}
      mask={{ closable: false }}
      destroyOnHidden
      width={760}
      className="dms_server_group_modal"
      footer={[
        <Button key="close" onClick={onClose} className="dms_server_group_close_btn">
          Close
        </Button>,
        <Button key="save" type="primary" loading={isSubmitting} onClick={() => form.submit()} className="dms_server_group_save_btn">
          Save
        </Button>,
      ]}
    >
      <Form<CreateServerGroupInput>
        form={form}
        layout="vertical"
        requiredMark
        onFinish={handleSubmit}
        initialValues={{ hosting_classification: "vps", auth_method: "ssh", connector_type: "cpanel", ssh_port: 22 }}
        className="dms_server_group_form"
      >
        <Form.Item
          name="connector_type"
          label="Connector Type"
          extra={isEditing ? "The connector type is fixed once a server is created. To use another type, add a new server group." : undefined}
          className="dms_server_group_connector_type_field"
        >
          <ConnectorCards isLocked={isEditing} />
        </Form.Item>

        {!isCpanel && appIp && (
          <Alert
            type="info"
            showIcon
            className="mb-3 dms_server_app_ip_alert"
            title={
              <span className="flex items-center gap-1 flex-wrap">
                This app connects from <span className="font-mono">{appIp}</span>
                <CopyIpButton ip={appIp} />
              </span>
            }
            description={
              hasBtPanel && usesSsh
                ? "Allow this address on the SSH port and the panel port in the cloud security group and the server firewall, and add it to the BT Panel API whitelist."
                : hasBtPanel
                  ? "Allow this address on the panel port in the cloud security group and the BT Panel firewall, and add it to the BT Panel API whitelist (Settings > API Interface)."
                  : "Allow this address on the SSH port in the cloud security group and the server firewall."
            }
          />
        )}

        <Section icon={<CloudServerOutlined />} title="Server" hint="How this server is named and reached." className="dms_server_section_basics">
          <div className="grid grid-cols-1 sm:grid-cols-2 gap-x-4">
            <Form.Item name="label" label="Label" rules={[{ required: true, message: "Give it a label" }]} className="dms_server_group_label_field">
              <Input placeholder="MY-CORE-1" autoFocus />
            </Form.Item>
            {!isBt && (
              <Form.Item name="ip_address" label="IP Address" className="dms_server_group_ip_field">
                <Input placeholder="203.0.113.10" />
              </Form.Item>
            )}
          </div>
          {(isCpanel || isAws) && (
            <Form.Item
              name="url"
              label={isCpanel ? "WHM URL" : "URL"}
              className="dms_server_group_url_field"
            >
              <Input placeholder={isCpanel ? "https://whm.example.com:2087" : "https://ec2-example.compute.amazonaws.com"} />
            </Form.Item>
          )}
          {isCloud && usesSsh && (
            <Form.Item name="web_root_base" label="Web Root Base" extra="One folder per domain under this path." className="dms_server_group_web_root_base_field">
              <Input placeholder="/var/www" />
            </Form.Item>
          )}
        </Section>

        {hasBtPanel && (
          <Section icon={<ApiOutlined />} title="BT Panel API" hint="Panel Settings > API Interface: copy the key and whitelist this server's IP." className="dms_server_section_bt">
            <Form.Item
              name="url"
              label="BT Panel URL"
              rules={[{ required: true, message: "The BT Panel address, including the port" }]}
              className="dms_server_group_url_field"
            >
              <Input placeholder="https://panel.example.com:8888" />
            </Form.Item>
            <Form.Item
              name="bt_api_key"
              label="BT Panel API Key"
              extra={isEditing ? "Leave blank to keep the current key." : undefined}
              className="dms_server_group_bt_api_key_field"
            >
              <Input.Password autoComplete="new-password" />
            </Form.Item>
          </Section>
        )}

        {isCloud && (
          <Section
            icon={<ApiOutlined />}
            title={isHuawei ? "Huawei Cloud API" : "AWS API"}
            hint={isHuawei ? "Used for the ECS status check and firewall (security group) rules." : "Used for the instance health check and security group rules."}
            className="dms_server_section_cloud"
          >
            <div className="grid grid-cols-1 sm:grid-cols-2 gap-x-4">
              <Form.Item name="aws_region" label={isHuawei ? "Huawei Region" : "AWS Region"} className="dms_server_group_aws_region_field">
                <Input placeholder={isHuawei ? "ap-southeast-3" : "ap-southeast-1"} />
              </Form.Item>
              {isHuawei && (
                <Form.Item
                  name="huawei_project_id"
                  label="Huawei Project ID"
                  extra="My Credentials > API Credentials."
                  className="dms_server_group_huawei_project_id_field"
                >
                  <Input placeholder="Project ID of the region" />
                </Form.Item>
              )}
              <Form.Item
                name="aws_instance_id"
                label={isHuawei ? "ECS Server ID" : "EC2 Instance ID"}
                extra={isHuawei ? "Paste the ID exactly as it is shown - both 24 and 36 character IDs are accepted." : undefined}
                className="dms_server_group_aws_instance_id_field"
              >
                <Input placeholder={isHuawei ? "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" : "i-0123456789abcdef0"} />
              </Form.Item>
              <Form.Item name="aws_security_group_id" label="Security Group ID" className="dms_server_group_aws_security_group_id_field">
                <Input placeholder={isHuawei ? "Security group ID" : "sg-0123456789abcdef0"} />
              </Form.Item>
              <Form.Item
                name="aws_access_key_id"
                label={isHuawei ? "Access Key (AK)" : "IAM Access Key ID"}
                extra={keepNote}
                className="dms_server_group_aws_access_key_id_field"
              >
                <Input.Password autoComplete="new-password" />
              </Form.Item>
              <Form.Item
                name="aws_secret_access_key"
                label={isHuawei ? "Secret Key (SK)" : "IAM Secret Access Key"}
                extra={keepNote}
                className="dms_server_group_aws_secret_access_key_field"
              >
                <Input.Password autoComplete="new-password" />
              </Form.Item>
            </div>
            {isHuawei && (
              <div className="flex flex-col gap-2 mb-3 dms_server_group_locate">
                <Button icon={<SearchOutlined />} loading={isLocating} onClick={() => void handleLocate()} className="w-fit dms_server_group_locate_btn">
                  Find my server by IP
                </Button>
                {locateResult && (
                  <Alert
                    type={locateResult.matches.length > 0 ? "success" : "warning"}
                    showIcon
                    title={
                      locateResult.error ??
                      (locateResult.matches.length > 0
                        ? "Found it in your Huawei account:"
                        : `No server with that IP in this account (regions checked: ${locateResult.scanned.join(", ") || "none"}).`)
                    }
                    description={
                      locateResult.matches.length > 0 ? (
                        <div className="flex flex-col gap-2">
                          {locateResult.matches.map((match) => (
                            <div key={match.server_id} className="flex items-center justify-between gap-2 flex-wrap">
                              <span>
                                {match.name} ({match.status}) - {match.region}, ECS ID <span className="font-mono">{match.server_id}</span>
                              </span>
                              <Button size="small" type="primary" onClick={() => applyLocated(match)}>
                                Use these
                              </Button>
                            </div>
                          ))}
                        </div>
                      ) : undefined
                    }
                  />
                )}
              </div>
            )}
          </Section>
        )}

        {usesSsh && (
          <Section
            icon={authMethod === "api" ? <KeyOutlined /> : <LockOutlined />}
            title="Login"
            hint={authMethod === "api" ? "The WHM API user and token." : connectorType === "huawei" ? "Optional. The SSH account the app deploys with - leave it empty if the files are managed through a BT Panel." : "The SSH account the app deploys with."}
            className="dms_server_section_login"
          >
            <Form.Item name="auth_method" label="Connect Via" className="dms_server_group_auth_method_field">
              <Radio.Group
                optionType="button"
                buttonStyle="solid"
                options={[
                  { value: "ssh", label: "SSH" },
                  ...(isCpanel ? [{ value: "api", label: "API" }] : []),
                ]}
              />
            </Form.Item>

            {authMethod === "api" && isCpanel ? (
              <div className="grid grid-cols-1 sm:grid-cols-2 gap-x-4">
                <Form.Item name="whm_username" label="API User" className="dms_server_group_api_user_field">
                  <Input />
                </Form.Item>
                <Form.Item name="whm_api_token" label="API Token" extra={isEditing ? "Leave blank to keep the current token." : undefined} className="dms_server_group_api_token_field">
                  <Input.Password autoComplete="new-password" />
                </Form.Item>
              </div>
            ) : (
              <>
                <div className="grid grid-cols-1 sm:grid-cols-2 gap-x-4">
                  <Form.Item name="ssh_username" label="SSH User" className="dms_server_group_ssh_username_field">
                    <Input placeholder="root" />
                  </Form.Item>
                  <Form.Item name="ssh_port" label="SSH Port" className="dms_server_group_ssh_port_field">
                    <InputNumber min={1} max={65535} className="w-full" />
                  </Form.Item>
                </div>
                <Form.Item
                  label="SSH Key File (.pem)"
                  extra={isEditing ? "Leave unset to keep the current key." : "Uploaded as text - never re-downloadable."}
                  className="dms_server_group_ssh_key_upload_field"
                >
                  <Upload
                    maxCount={1}
                    accept=".pem,.key"
                    beforeUpload={(file) => {
                      const reader = new FileReader();
                      reader.onload = () => form.setFieldValue("ssh_key", reader.result as string);
                      reader.readAsText(file);
                      return false;
                    }}
                  >
                    <Button icon={<UploadOutlined />}>Choose File</Button>
                  </Upload>
                </Form.Item>
                <Form.Item name="ssh_key" hidden className="dms_server_group_ssh_key_field">
                  <Input />
                </Form.Item>
                <Form.Item
                  name="ssh_password"
                  label="SSH Password / Key Passphrase"
                  extra={
                    isEditing
                      ? "Leave blank to keep the current value. Only needed if you're not using a key, or your key has a passphrase."
                      : "Only needed if you're not using a key above, or your key has a passphrase."
                  }
                  className="dms_server_group_ssh_password_field"
                >
                  <Input.Password autoComplete="new-password" />
                </Form.Item>
              </>
            )}
          </Section>
        )}

        {isCloud && usesSsh && (
          <Section icon={<DatabaseOutlined />} title="WordPress database" hint="Used to create WordPress databases over SSH." className="dms_server_section_db">
            <div className="grid grid-cols-1 sm:grid-cols-2 gap-x-4">
              <Form.Item name="db_admin_username" label="DB Admin Username" className="dms_server_group_db_admin_username_field">
                <Input placeholder="root" />
              </Form.Item>
              <Form.Item name="db_admin_password" label="DB Admin Password" extra={keepNote} className="dms_server_group_db_admin_password_field">
                <Input.Password autoComplete="new-password" />
              </Form.Item>
            </div>
          </Section>
        )}

        <Collapse
          ghost
          className="dms_server_advanced"
          items={[
            {
              key: "advanced",
              forceRender: true,
              label: "Advanced (Optional)",
              children: (
                <>
                  <div className="grid grid-cols-1 sm:grid-cols-2 gap-x-4">
                    {isCpanel && (
                      <Form.Item name="whm_host" label="WHM Host" className="dms_server_group_whm_host_field">
                        <Input placeholder="whm.example.com" />
                      </Form.Item>
                    )}
                    {isBt && (
                      <Form.Item name="ip_address" label="IP Address" className="dms_server_group_ip_field">
                        <Input placeholder="203.0.113.10" />
                      </Form.Item>
                    )}
                    <Form.Item name="hosting_classification" label="Hosting Classification" className="dms_server_group_classification_field">
                      <Select options={CLASSIFICATION_OPTIONS} />
                    </Form.Item>
                    <Form.Item name="provider" label="Provider" className="dms_server_group_provider_field">
                      <Input placeholder="DigitalOcean" />
                    </Form.Item>
                    <Form.Item name="location" label="Location" className="dms_server_group_location_field">
                      <Input placeholder="SG" />
                    </Form.Item>
                    <Form.Item name="capacity_static" label="Static Account Limit" className="dms_server_group_capacity_static_field">
                      <InputNumber min={0} className="w-full" />
                    </Form.Item>
                    <Form.Item name="capacity_wp" label="WordPress Account Limit" className="dms_server_group_capacity_wp_field">
                      <InputNumber min={0} className="w-full" />
                    </Form.Item>
                  </div>
                </>
              ),
            },
          ]}
        />
      </Form>
    </Modal>
  );
}
