"use client";

import type {
  CloudflareDnsRecord,
  CloudflareProvisionStep,
  CloudflareSecurityRule,
  CloudflareVerifyCheck,
  Domain,
} from "@domainops/shared-types";
import { App, Button, Card, Checkbox, Form, Input, Popconfirm, Select, Space, Switch, Table, Tabs, Tag } from "antd";
import { useCallback, useEffect, useState } from "react";
import {
  createDnsRecord,
  createSecurityRule,
  deleteDnsRecord,
  deleteSecurityRule,
  listDnsRecords,
  listSecurityRules,
  provisionCloudflare,
  purgeCache,
  toggleCloudflareProxy,
  verifyCloudflareProvisioning,
} from "@/lib/api/cloudflare";
import { addSubdomain } from "@/lib/api/domains";
import { ApiError } from "@/lib/api/client";
import { SecurityPresets } from "@/components/features/SecurityPresets";
import type { PresetRule } from "@/components/features/SecurityPresets";

function DnsRecordsSection({ domainId, domainName, subdomainNames, onSubdomainAdded }: { domainId: number; domainName: string; subdomainNames: string[]; onSubdomainAdded: () => void }) {
  const { message } = App.useApp();
  const [records, setRecords] = useState<CloudflareDnsRecord[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [form] = Form.useForm();
  const recordType = Form.useWatch("type", form);

  const load = useCallback(async () => {
    setIsLoading(true);
    try {
      setRecords(await listDnsRecords(domainId));
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't load DNS records.");
    } finally {
      setIsLoading(false);
    }
  }, [domainId, message]);

  useEffect(() => {
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void load();
  }, [load]);

  async function handleCreate(values: { type: string; name: string; content: string; proxied?: boolean; as_subdomain?: boolean }) {
    const { as_subdomain: asSubdomain, ...record } = values;
    try {
      await createDnsRecord(domainId, record);
      message.success("DNS record created.");
      if (asSubdomain) {
        await addSubdomain(domainId, record.name);
        message.success("Listed as a sub-domain in Domain Inventory.");
        onSubdomainAdded();
      }
      form.resetFields();
      void load();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't create the DNS record.");
    }
  }

  async function handleAddSubdomain(record: CloudflareDnsRecord) {
    try {
      await addSubdomain(domainId, record.name);
      message.success(`${record.name} is now listed as a sub-domain.`);
      onSubdomainAdded();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't add that sub-domain.");
    }
  }

  async function handleDelete(recordId: string) {
    try {
      await deleteDnsRecord(domainId, recordId);
      message.success("DNS record deleted.");
      void load();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't delete the DNS record.");
    }
  }

  return (
    <div>
      <Form
        form={form}
        layout="inline"
        onFinish={handleCreate}
        className="mb-3 flex-wrap gap-2 dms_domain_cloudflare_panel_dns_form"
      >
        <Form.Item name="type" initialValue="A" rules={[{ required: true }]} className="dms_domain_cloudflare_panel_dns_type_field">
          <Select
            style={{ width: 90 }}
            options={["A", "AAAA", "CNAME", "TXT", "MX", "NS"].map((t) => ({ value: t, label: t }))}
          />
        </Form.Item>
        <Form.Item name="name" rules={[{ required: true, message: "Name" }]} className="dms_domain_cloudflare_panel_dns_name_field">
          <Input placeholder="sub.example.com" />
        </Form.Item>
        <Form.Item name="content" rules={[{ required: true, message: "Content" }]} className="dms_domain_cloudflare_panel_dns_content_field">
          <Input placeholder="1.2.3.4" />
        </Form.Item>
        <Form.Item name="proxied" valuePropName="checked" initialValue={false} className="dms_domain_cloudflare_panel_dns_proxied_field">
          <Switch aria-label="Proxy this record" checkedChildren="Proxied" unCheckedChildren="DNS only" />
        </Form.Item>
        {["A", "AAAA", "CNAME"].includes(recordType) && (
          <Form.Item name="as_subdomain" valuePropName="checked" initialValue={false} className="dms_domain_cloudflare_panel_dns_subdomain_field">
            <Checkbox>List as a sub-domain in Domain Inventory</Checkbox>
          </Form.Item>
        )}
        <Form.Item className="dms_domain_cloudflare_panel_dns_submit_field">
          <Button type="primary" htmlType="submit" className="dms_domain_cloudflare_panel_dns_add_btn">
            Add record
          </Button>
        </Form.Item>
      </Form>
      <Table<CloudflareDnsRecord>
        size="small"
        rowKey="id"
        loading={isLoading}
        pagination={false}
        dataSource={records}
        className="dms_domain_cloudflare_panel_dns_table"
        columns={[
          { title: "Type", dataIndex: "type", width: 80 },
          { title: "Name", dataIndex: "name" },
          { title: "Content", dataIndex: "content" },
          {
            title: "Proxied",
            dataIndex: "proxied",
            width: 90,
            render: (v: boolean) => (v ? <Tag color="orange">proxied</Tag> : <Tag>dns only</Tag>),
          },
          {
            title: "Sub-domain",
            width: 140,
            render: (_, record) => {
              if (!["A", "AAAA", "CNAME"].includes(record.type) || record.name === domainName) return null;
              if (subdomainNames.includes(record.name)) return <Tag color="green">Listed</Tag>;

              return (
                <Button size="small" onClick={() => void handleAddSubdomain(record)} className="dms_domain_cloudflare_panel_dns_add_subdomain_btn">
                  Add as sub-domain
                </Button>
              );
            },
          },
          {
            title: "",
            width: 80,
            render: (_, record) => (
              <Popconfirm title="Delete this record?" onConfirm={() => handleDelete(record.id)}>
                <Button size="small" danger className="dms_domain_cloudflare_panel_dns_delete_btn">
                  Delete
                </Button>
              </Popconfirm>
            ),
          },
        ]}
      />
    </div>
  );
}

function SecurityRulesSection({ domainId }: { domainId: number }) {
  const { message } = App.useApp();
  const [rules, setRules] = useState<CloudflareSecurityRule[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [form] = Form.useForm();

  const load = useCallback(async () => {
    setIsLoading(true);
    try {
      setRules(await listSecurityRules(domainId));
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't load security rules.");
    } finally {
      setIsLoading(false);
    }
  }, [domainId, message]);

  useEffect(() => {
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void load();
  }, [load]);

  async function handlePreset(rule: PresetRule) {
    await createSecurityRule(domainId, rule);
    message.success(`${rule.description} - rule added.`);
    void load();
  }

  async function handleCreate(values: { description: string; expression: string; action: string }) {
    try {
      await createSecurityRule(domainId, values as never);
      message.success("Security rule created.");
      form.resetFields();
      void load();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't create the security rule.");
    }
  }

  async function handleDelete(ruleId: string) {
    try {
      await deleteSecurityRule(domainId, ruleId);
      message.success("Security rule deleted.");
      void load();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't delete the security rule.");
    }
  }

  return (
    <div>
      <SecurityPresets onCreate={handlePreset} />
      <p className="text-xs text-gray-500 mt-4 mb-2">
        Scope a rule to one subdomain with an expression like <code>http.host eq &quot;sub.example.com&quot;</code>.
      </p>
      <Form
        form={form}
        layout="inline"
        onFinish={handleCreate}
        className="mb-3 flex-wrap gap-2 dms_domain_cloudflare_panel_security_rule_form"
      >
        <Form.Item
          name="description"
          rules={[{ required: true, message: "Description" }]}
          className="dms_domain_cloudflare_panel_security_rule_description_field"
        >
          <Input placeholder="Block bad bots on sub.example.com" style={{ width: 220 }} />
        </Form.Item>
        <Form.Item
          name="expression"
          rules={[{ required: true, message: "Expression" }]}
          className="dms_domain_cloudflare_panel_security_rule_expression_field"
        >
          <Input placeholder='http.host eq "sub.example.com"' style={{ width: 240 }} />
        </Form.Item>
        <Form.Item
          name="action"
          initialValue="block"
          rules={[{ required: true }]}
          className="dms_domain_cloudflare_panel_security_rule_action_field"
        >
          <Select
            style={{ width: 130 }}
            options={["block", "challenge", "js_challenge", "allow", "log"].map((a) => ({ value: a, label: a }))}
          />
        </Form.Item>
        <Form.Item className="dms_domain_cloudflare_panel_security_rule_submit_field">
          <Button type="primary" htmlType="submit" className="dms_domain_cloudflare_panel_security_rule_add_btn">
            Add rule
          </Button>
        </Form.Item>
      </Form>
      <Table<CloudflareSecurityRule>
        size="small"
        rowKey="id"
        loading={isLoading}
        pagination={false}
        dataSource={rules}
        className="dms_domain_cloudflare_panel_security_rule_table"
        columns={[
          { title: "Description", dataIndex: "description" },
          { title: "Expression", dataIndex: "expression" },
          { title: "Action", dataIndex: "action", width: 100 },
          {
            title: "",
            width: 80,
            render: (_, record) => (
              <Popconfirm title="Delete this rule?" onConfirm={() => handleDelete(record.id)}>
                <Button size="small" danger className="dms_domain_cloudflare_panel_security_rule_delete_btn">
                  Delete
                </Button>
              </Popconfirm>
            ),
          },
        ]}
      />
    </div>
  );
}

export function CloudflarePanel({
  domain,
  hasServer,
  onUpdated,
  onSubdomainAdded,
}: {
  domain: Domain;
  hasServer: boolean;
  onUpdated: (domain: Domain) => void;
  onSubdomainAdded?: () => void;
}) {
  const { message } = App.useApp();
  const [isProvisioning, setIsProvisioning] = useState(false);
  const [isTogglingProxy, setIsTogglingProxy] = useState(false);
  const [isPurging, setIsPurging] = useState(false);
  const [lastSteps, setLastSteps] = useState<CloudflareProvisionStep[] | null>(null);
  const [isVerifying, setIsVerifying] = useState(false);
  const [verifyChecks, setVerifyChecks] = useState<CloudflareVerifyCheck[] | null>(null);

  const canLinkAccount = !!domain.cloudflare_account || !!domain.brand;
  const isProvisioned = !!domain.cf_zone_id;

  async function handleProvision() {
    setIsProvisioning(true);
    try {
      const result = await provisionCloudflare(domain.id);
      setLastSteps(result.steps);
      onUpdated(result.domain);
      message.success("Cloudflare provisioning finished.");
    } catch (err) {
      if (err instanceof ApiError) {
        message.error(err.message);
        const steps = err.errors as unknown as { steps?: CloudflareProvisionStep[] } | null;
        if (steps?.steps) setLastSteps(steps.steps);
      } else {
        message.error("Couldn't provision Cloudflare.");
      }
    } finally {
      setIsProvisioning(false);
    }
  }

  async function handleVerify() {
    setIsVerifying(true);
    try {
      const checks = await verifyCloudflareProvisioning(domain.id);
      setVerifyChecks(checks);
      const allPass = checks.every((c) => c.status === "pass");
      if (allPass) {
        message.success("Everything checks out.");
      } else {
        message.warning("Some checks did not pass.");
      }
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't verify provisioning.");
    } finally {
      setIsVerifying(false);
    }
  }

  async function handleToggleProxy(checked: boolean) {
    setIsTogglingProxy(true);
    try {
      const updated = await toggleCloudflareProxy(domain.id, checked);
      onUpdated(updated);
      message.success(checked ? "Proxying enabled." : "Proxying disabled.");
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't change proxying.");
    } finally {
      setIsTogglingProxy(false);
    }
  }

  async function handlePurgeCache() {
    setIsPurging(true);
    try {
      await purgeCache(domain.id);
      message.success("Cache purged.");
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't purge the cache.");
    } finally {
      setIsPurging(false);
    }
  }

  return (
    <Card title="Cloudflare" className="cloudflare-panel dms_domain_cloudflare_panel_card">
      {!hasServer && (
        <p className="text-sm text-amber-600 mb-3">Assign this domain to a server before provisioning Cloudflare.</p>
      )}
      {!canLinkAccount && (
        <p className="text-sm text-amber-600 mb-3">
          Link a Cloudflare account to this domain&apos;s project (or the domain directly) before provisioning.
        </p>
      )}

      <div className="flex items-center gap-3 mb-4">
        <span>Zone:</span>
        <Tag color={isProvisioned ? "green" : "default"}>{isProvisioned ? domain.cf_zone_id : "not provisioned"}</Tag>
      </div>

      <div className="flex items-center gap-3 mb-4">
        <Switch
          aria-label="Proxying"
          checked={domain.proxied}
          onChange={handleToggleProxy}
          disabled={!isProvisioned}
          loading={isTogglingProxy}
        />
        <span>{domain.proxied ? "Proxied (orange cloud)" : "DNS only"}</span>
      </div>

      <Space className="mb-4" wrap>
        <Popconfirm
          title={isProvisioned ? "Re-run Cloudflare provisioning?" : "Provision this domain with Cloudflare?"}
          description="Creates/reuses the zone, writes DNS, applies security defaults, and switches nameservers at the registrar."
          onConfirm={handleProvision}
          disabled={!hasServer || !canLinkAccount}
        >
          <Button
            type="primary"
            loading={isProvisioning}
            disabled={!hasServer || !canLinkAccount}
            className="dms_domain_cloudflare_panel_provision_btn"
          >
            {isProvisioned ? "Re-provision" : "Provision"}
          </Button>
        </Popconfirm>
        <Popconfirm title="Purge everything in this zone's cache?" onConfirm={handlePurgeCache} disabled={!isProvisioned}>
          <Button loading={isPurging} disabled={!isProvisioned} className="dms_domain_cloudflare_panel_purge_btn">
            Purge cache
          </Button>
        </Popconfirm>
        <Button
          loading={isVerifying}
          disabled={!isProvisioned}
          onClick={handleVerify}
          className="dms_domain_cloudflare_panel_verify_btn"
        >
          Verify
        </Button>
        {isProvisioned && domain.cloudflare_account && (
          <Button
            href={`https://dash.cloudflare.com/${domain.cloudflare_account.account_id}/${domain.fqdn}`}
            target="_blank"
            rel="noopener noreferrer"
            className="dms_domain_cloudflare_panel_open_dashboard_btn"
          >
            Open Cloudflare Dashboard
          </Button>
        )}
      </Space>

      {lastSteps && (
        <Table<CloudflareProvisionStep>
          className="mb-4 dms_domain_cloudflare_panel_steps_table"
          rowKey="step"
          size="small"
          pagination={false}
          dataSource={lastSteps}
          columns={[
            { title: "Step", dataIndex: "step" },
            {
              title: "Result",
              dataIndex: "status",
              render: (v: "done" | "failed") => <Tag color={v === "done" ? "green" : "red"}>{v}</Tag>,
            },
            { title: "Message", dataIndex: "message" },
          ]}
        />
      )}

      {verifyChecks && (
        <Table<CloudflareVerifyCheck>
          className="mb-4 dms_domain_cloudflare_panel_verify_table"
          rowKey="check"
          size="small"
          pagination={false}
          dataSource={verifyChecks}
          columns={[
            { title: "Check", dataIndex: "check" },
            {
              title: "Result",
              dataIndex: "status",
              render: (v: "pass" | "fail") => <Tag color={v === "pass" ? "green" : "red"}>{v}</Tag>,
            },
            { title: "Message", dataIndex: "message" },
          ]}
        />
      )}

      {isProvisioned && (
        <Tabs
          size="small"
          items={[
            { key: "dns", label: "DNS records", children: (
                <DnsRecordsSection
                  domainId={domain.id}
                  domainName={domain.fqdn}
                  subdomainNames={(domain.subdomains ?? []).map((s) => s.fqdn)}
                  onSubdomainAdded={onSubdomainAdded ?? (() => undefined)}
                />
              ), },
            { key: "security", label: "Security rules", children: <SecurityRulesSection domainId={domain.id} /> },
          ]}
        />
      )}
    </Card>
  );
}
