"use client";

import type {
  CloudflareAccount,
  CloudflareDnsRecord,
  CloudflarePageRule,
  CloudflareRedirectRule,
  CloudflareSecurityAction,
  CloudflareSecurityRule,
  CloudflareZone,
} from "@domainops/shared-types";
import { App, Button, Form, Input, InputNumber, Modal, Popconfirm, Select, Switch, Table, Tabs, Tag, Typography } from "antd";
import { DeleteOutlined } from "@ant-design/icons";
import type { ColumnsType } from "antd/es/table";
import { useCallback, useEffect, useState } from "react";
import {
  createZoneDnsRecord,
  createZonePageRule,
  createZoneRedirectRule,
  createZoneSecurityRule,
  deleteZoneDnsRecord,
  deleteZonePageRule,
  deleteZoneRedirectRule,
  deleteZoneSecurityRule,
  listCloudflareZones,
  listZoneDnsRecords,
  listZonePageRules,
  listZoneRedirectRules,
  listZoneSecurityRules,
} from "@/lib/api/cloudflare";
import { ApiError } from "@/lib/api/client";
import { ExpressionBuilder } from "@/components/features/ExpressionBuilder";
import { COUNTRY_OPTIONS } from "@/lib/utils/countries";
import { conditionToExpression } from "@/lib/utils/cfExpression";
import type { FieldKey } from "@/lib/utils/cfExpression";

interface SecurityRuleFormValues {
  description: string;
  expression: string;
  action: CloudflareSecurityAction;
}

interface QuickRule {
  key: string;
  label: string;
  action: CloudflareSecurityAction;
  field: FieldKey;
  valueLabel: string;
  placeholder: string;
}

const ACTION_OPTIONS: { value: CloudflareSecurityAction; label: string }[] = [
  { value: "block", label: "Block" },
  { value: "allow", label: "Allow" },
  { value: "challenge", label: "Managed Challenge" },
  { value: "js_challenge", label: "JS Challenge" },
  { value: "log", label: "Log Only" },
];

const QUICK_RULES: QuickRule[] = [
  { key: "allow_ip", label: "Allow IP", action: "allow", field: "ip", valueLabel: "IP addresses", placeholder: "203.0.113.10" },
  { key: "block_ip", label: "Block IP", action: "block", field: "ip", valueLabel: "IP addresses", placeholder: "198.51.100.7" },
  { key: "allow_region", label: "Allow Region", action: "allow", field: "country", valueLabel: "Countries", placeholder: "Pick countries" },
  { key: "block_region", label: "Block Region", action: "block", field: "country", valueLabel: "Countries", placeholder: "Pick countries" },
  { key: "challenge_region", label: "Challenge Region", action: "challenge", field: "country", valueLabel: "Countries", placeholder: "Pick countries" },
  { key: "block_user_agent", label: "Block User Agent", action: "block", field: "user_agent", valueLabel: "User agent contains", placeholder: "BadBot" },
  { key: "block_path", label: "Block Path", action: "block", field: "path", valueLabel: "Path starts with", placeholder: "/wp-admin" },
];

interface QuickRuleFormValues {
  values: string[];
  description: string;
}

interface PageRuleFormValues {
  target_url_pattern: string;
  forwarding_url: string;
  status_code: 301 | 302;
}

interface RedirectRuleFormValues {
  description: string;
  expression: string;
  target_url: string;
  status_code: 301 | 302;
  preserve_query_string: boolean;
}

interface DnsRecordFormValues {
  type: string;
  name: string;
  content: string;
  proxied?: boolean;
}

const FORM_GRID_STYLE = { display: "grid", gap: "0 16px" } as const;

/**
 * Manages a zone directly by zone_id, before it's necessarily linked to a
 * Domain row yet (or for one that never will be, e.g. Settings > Security's
 * "protect this app's own domain") - see CloudflareZoneRulesController's
 * docblock. Purge cache stays on the per-Domain Cloudflare panel; nothing
 * here caches arbitrary content the way a provisioned domain's zone does.
 * The Redirects tab manages Cloudflare's own edge-level redirect rules
 * (Rulesets API, http_request_dynamic_redirect phase).
 *
 * Security rules are added two ways: one-click presets (Allow IP, Block
 * Region ...) that only ask for the value, or a custom rule whose condition
 * is assembled with the expression builder (AND / OR across several
 * conditions) rather than typed as raw Cloudflare syntax.
 */
export function ZoneSecurityModal({
  open,
  account,
  initialZoneId,
  onClose,
}: {
  open: boolean;
  account: CloudflareAccount | null;
  initialZoneId?: string;
  onClose: () => void;
}) {
  const { message } = App.useApp();
  const [zones, setZones] = useState<CloudflareZone[]>([]);
  const [zoneId, setZoneId] = useState<string | undefined>();
  const [isLoadingZones, setIsLoadingZones] = useState(false);
  const [dnsRecords, setDnsRecords] = useState<CloudflareDnsRecord[]>([]);
  const [securityRules, setSecurityRules] = useState<CloudflareSecurityRule[]>([]);
  const [pageRules, setPageRules] = useState<CloudflarePageRule[]>([]);
  const [redirectRules, setRedirectRules] = useState<CloudflareRedirectRule[]>([]);
  const [isLoadingRules, setIsLoadingRules] = useState(false);
  const [quickRule, setQuickRule] = useState<QuickRule | null>(null);
  const [dnsForm] = Form.useForm<DnsRecordFormValues>();
  const [securityForm] = Form.useForm<SecurityRuleFormValues>();
  const [quickForm] = Form.useForm<QuickRuleFormValues>();
  const [pageRuleForm] = Form.useForm<PageRuleFormValues>();
  const [redirectRuleForm] = Form.useForm<RedirectRuleFormValues>();

  useEffect(() => {
    if (!open || !account) return;
    // eslint-disable-next-line react-hooks/set-state-in-effect
    setIsLoadingZones(true);
    setZoneId(initialZoneId);
    listCloudflareZones(account.id)
      .then(setZones)
      .catch((err) => message.error(err instanceof ApiError ? err.message : "Couldn't load zones."))
      .finally(() => setIsLoadingZones(false));
    // initialZoneId is only meant to seed the very first open, not resync
    // whenever the parent happens to re-render.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, account, message]);

  const loadRules = useCallback(async () => {
    if (!account || !zoneId) return;
    setIsLoadingRules(true);
    try {
      const [dns, security, page, redirects] = await Promise.all([
        listZoneDnsRecords(account.id, zoneId),
        listZoneSecurityRules(account.id, zoneId),
        listZonePageRules(account.id, zoneId),
        listZoneRedirectRules(account.id, zoneId),
      ]);
      setDnsRecords(dns);
      setSecurityRules(security);
      setPageRules(page);
      setRedirectRules(redirects);
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't load this zone's rules.");
    } finally {
      setIsLoadingRules(false);
    }
  }, [account, zoneId, message]);

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

  async function handleAddDnsRecord(values: DnsRecordFormValues) {
    if (!account || !zoneId) return;
    try {
      await createZoneDnsRecord(account.id, zoneId, values);
      message.success("DNS record created.");
      dnsForm.resetFields();
      void loadRules();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't create that DNS record.");
    }
  }

  async function handleDeleteDnsRecord(recordId: string) {
    if (!account || !zoneId) return;
    try {
      await deleteZoneDnsRecord(account.id, zoneId, recordId);
      message.success("DNS record deleted.");
      void loadRules();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't delete that DNS record.");
    }
  }

  async function handleAddSecurityRule(values: SecurityRuleFormValues) {
    if (!account || !zoneId) return;
    try {
      await createZoneSecurityRule(account.id, zoneId, values);
      message.success("Security rule added.");
      securityForm.resetFields(["description"]);
      void loadRules();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't add that rule.");
    }
  }

  function openQuickRule(rule: QuickRule) {
    setQuickRule(rule);
    quickForm.resetFields();
  }

  async function handleQuickRule(values: QuickRuleFormValues) {
    if (!account || !zoneId || !quickRule) return;

    const operator = quickRule.field === "user_agent" ? "contains" : quickRule.field === "path" ? "starts_with" : values.values.length > 1 ? "in" : "eq";
    const expression = conditionToExpression({ field: quickRule.field, operator, values: values.values, join: "and" });

    if (!expression) {
      message.error(quickRule.field === "ip" ? "Enter valid IP addresses, for example 203.0.113.10 or 203.0.113.0/24." : "Check the value you entered.");
      return;
    }

    try {
      await createZoneSecurityRule(account.id, zoneId, {
        description: values.description || `${quickRule.label}: ${values.values.join(", ")}`,
        expression,
        action: quickRule.action,
      });
      message.success(`${quickRule.label} rule added.`);
      setQuickRule(null);
      void loadRules();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't add that rule.");
    }
  }

  async function handleDeleteSecurityRule(ruleId: string) {
    if (!account || !zoneId) return;
    try {
      await deleteZoneSecurityRule(account.id, zoneId, ruleId);
      message.success("Rule removed.");
      void loadRules();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't remove that rule.");
    }
  }

  async function handleAddPageRule(values: PageRuleFormValues) {
    if (!account || !zoneId) return;
    try {
      await createZonePageRule(account.id, zoneId, values);
      message.success("Page rule created.");
      pageRuleForm.resetFields();
      void loadRules();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't create that page rule.");
    }
  }

  async function handleDeletePageRule(ruleId: string) {
    if (!account || !zoneId) return;
    try {
      await deleteZonePageRule(account.id, zoneId, ruleId);
      message.success("Page rule deleted.");
      void loadRules();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't delete that page rule.");
    }
  }

  async function handleAddRedirectRule(values: RedirectRuleFormValues) {
    if (!account || !zoneId) return;
    try {
      await createZoneRedirectRule(account.id, zoneId, values);
      message.success("Redirect rule created.");
      redirectRuleForm.resetFields(["description", "target_url"]);
      void loadRules();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't create that redirect rule.");
    }
  }

  async function handleDeleteRedirectRule(ruleId: string) {
    if (!account || !zoneId) return;
    try {
      await deleteZoneRedirectRule(account.id, zoneId, ruleId);
      message.success("Redirect rule deleted.");
      void loadRules();
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't delete that redirect rule.");
    }
  }

  const securityColumns: ColumnsType<CloudflareSecurityRule> = [
    { title: "Label", dataIndex: "description" },
    {
      title: "Action",
      dataIndex: "action",
      render: (v: string) => (
        <Tag color={v === "block" ? "red" : v === "allow" ? "green" : "default"}>
          {ACTION_OPTIONS.find((a) => a.value === v)?.label ?? v}
        </Tag>
      ),
    },
    { title: "Expression", dataIndex: "expression", render: (v: string) => <span className="font-mono text-xs">{v}</span> },
    {
      title: "",
      render: (_, rule) => (
        <Button
          size="small"
          danger
          icon={<DeleteOutlined />}
          onClick={() => handleDeleteSecurityRule(rule.id)}
          className="dms_zone_security_remove_rule_btn"
        />
      ),
    },
  ];

  const pageRuleColumns: ColumnsType<CloudflarePageRule> = [
    { title: "Target", dataIndex: "target_url" },
    { title: "Forwards to", dataIndex: "forwarding_url", render: (v: string | null) => v ?? "—" },
    { title: "Status", dataIndex: "status" },
    {
      title: "",
      render: (_, rule) => (
        <Button
          size="small"
          danger
          icon={<DeleteOutlined />}
          onClick={() => handleDeletePageRule(rule.id)}
          className="dms_zone_page_rule_remove_btn"
        />
      ),
    },
  ];

  const redirectRuleColumns: ColumnsType<CloudflareRedirectRule> = [
    { title: "Label", dataIndex: "description" },
    { title: "Expression", dataIndex: "expression", render: (v: string) => <span className="font-mono text-xs">{v}</span> },
    { title: "Target", dataIndex: "target_url" },
    { title: "Status", dataIndex: "status_code" },
    {
      title: "",
      render: (_, rule) => (
        <Button
          size="small"
          danger
          icon={<DeleteOutlined />}
          onClick={() => handleDeleteRedirectRule(rule.id)}
          className="dms_zone_redirect_rule_remove_btn"
        />
      ),
    },
  ];

  const dnsColumns: ColumnsType<CloudflareDnsRecord> = [
    { title: "Type", dataIndex: "type", width: 80 },
    { title: "Name", dataIndex: "name" },
    { title: "Content", dataIndex: "content" },
    {
      title: "Proxied",
      dataIndex: "proxied",
      width: 100,
      render: (v: boolean) => (v ? <Tag color="orange">Proxied</Tag> : <Tag>DNS Only</Tag>),
    },
    {
      title: "",
      render: (_, record) => (
        <Popconfirm title="Delete this record?" onConfirm={() => handleDeleteDnsRecord(record.id)}>
          <Button size="small" danger className="dms_zone_dns_record_remove_btn">
            Delete
          </Button>
        </Popconfirm>
      ),
    },
  ];

  const dnsTab = (
    <div>
      <Form<DnsRecordFormValues> form={dnsForm} layout="vertical" onFinish={handleAddDnsRecord} className="mb-3 dms_zone_dns_form">
        <div style={{ ...FORM_GRID_STYLE, gridTemplateColumns: "100px 1fr 1fr 140px" }}>
          <Form.Item label="Type" name="type" initialValue="A" rules={[{ required: true }]} className="dms_zone_dns_type_field">
            <Select options={["A", "AAAA", "CNAME", "TXT", "MX", "NS"].map((t) => ({ value: t, label: t }))} />
          </Form.Item>
          <Form.Item label="Name" name="name" rules={[{ required: true, message: "Enter the name" }]} className="dms_zone_dns_name_field">
            <Input placeholder="sub.example.com" />
          </Form.Item>
          <Form.Item label="Content" name="content" rules={[{ required: true, message: "Enter the content" }]} className="dms_zone_dns_content_field">
            <Input placeholder="1.2.3.4" />
          </Form.Item>
          <Form.Item label="Proxy status" name="proxied" valuePropName="checked" initialValue={false} className="dms_zone_dns_proxied_field">
            <Switch aria-label="Proxy this record" checkedChildren="Proxied" unCheckedChildren="DNS only" />
          </Form.Item>
        </div>
        <Button type="primary" htmlType="submit" className="dms_zone_dns_add_btn">
          Add record
        </Button>
      </Form>
      <Table<CloudflareDnsRecord>
        size="small"
        rowKey="id"
        loading={isLoadingRules}
        dataSource={dnsRecords}
        columns={dnsColumns}
        pagination={false}
        className="dms_zone_dns_records_table"
        locale={{ emptyText: "No DNS records loaded for this zone yet." }}
      />
    </div>
  );

  const securityTab = (
    <div className="flex flex-col gap-4">
      <div>
        <Typography.Text strong>Quick add</Typography.Text>
        <div className="flex gap-2 flex-wrap mt-2 dms_zone_security_quick_add">
          {QUICK_RULES.map((rule) => (
            <Button
              key={rule.key}
              size="small"
              danger={rule.action === "block"}
              onClick={() => openQuickRule(rule)}
              className={`dms_zone_security_quick_${rule.key}_btn`}
            >
              {rule.label}
            </Button>
          ))}
        </div>
      </div>

      <Form<SecurityRuleFormValues>
        form={securityForm}
        layout="vertical"
        onFinish={handleAddSecurityRule}
        initialValues={{ action: "block", expression: "" }}
        className="dms_zone_security_custom_form"
      >
        <Typography.Text strong>Custom rule</Typography.Text>
        <div style={{ ...FORM_GRID_STYLE, gridTemplateColumns: "1fr 220px", marginTop: 8 }}>
          <Form.Item label="Rule label" name="description" rules={[{ required: true, message: "Give the rule a label" }]} className="dms_zone_security_label_field">
            <Input placeholder="Block admin paths from outside Malaysia" />
          </Form.Item>
          <Form.Item label="Action" name="action" className="dms_zone_security_action_field">
            <Select options={ACTION_OPTIONS} />
          </Form.Item>
        </div>
        <Form.Item
          label="When the request matches"
          name="expression"
          rules={[{ required: true, message: "Complete the conditions" }]}
          className="dms_zone_security_expression_field"
        >
          <ExpressionBuilder />
        </Form.Item>
        <Button type="primary" htmlType="submit" className="dms_zone_security_add_btn">
          Add rule
        </Button>
      </Form>

      <Table<CloudflareSecurityRule>
        size="small"
        rowKey="id"
        loading={isLoadingRules}
        dataSource={securityRules}
        columns={securityColumns}
        pagination={false}
        className="dms_zone_security_rules_table"
        locale={{ emptyText: "No security rules on this zone yet." }}
      />
    </div>
  );

  const pageRulesTab = (
    <div>
      <Form<PageRuleFormValues>
        form={pageRuleForm}
        layout="vertical"
        onFinish={handleAddPageRule}
        initialValues={{ status_code: 301 }}
        className="mb-3 dms_zone_page_rule_form"
      >
        <div style={{ ...FORM_GRID_STYLE, gridTemplateColumns: "1fr 1fr 120px" }}>
          <Form.Item
            label="URL pattern"
            name="target_url_pattern"
            rules={[{ required: true, message: "e.g. example.com/old/*" }]}
            extra="Which addresses this rule applies to. Use * to match anything."
            className="dms_zone_page_rule_target_field"
          >
            <Input placeholder="example.com/old/*" />
          </Form.Item>
          <Form.Item
            label="Forwards to"
            name="forwarding_url"
            rules={[{ required: true, message: "Enter the destination" }]}
            className="dms_zone_page_rule_forward_field"
          >
            <Input placeholder="https://example.com/new/" />
          </Form.Item>
          <Form.Item label="Status code" name="status_code" className="dms_zone_page_rule_status_field">
            <InputNumber min={301} max={302} style={{ width: "100%" }} />
          </Form.Item>
        </div>
        <Button type="primary" htmlType="submit" className="dms_zone_page_rule_add_btn">
          Add page rule
        </Button>
      </Form>
      <Table<CloudflarePageRule>
        size="small"
        rowKey="id"
        loading={isLoadingRules}
        dataSource={pageRules}
        columns={pageRuleColumns}
        pagination={false}
        className="dms_zone_page_rules_table"
        locale={{ emptyText: "No page rules on this zone yet." }}
      />
    </div>
  );

  const redirectsTab = (
    <div>
      <Form<RedirectRuleFormValues>
        form={redirectRuleForm}
        layout="vertical"
        onFinish={handleAddRedirectRule}
        initialValues={{ status_code: 301, preserve_query_string: true, expression: "" }}
        className="mb-3 dms_zone_redirect_rule_form"
      >
        <div style={{ ...FORM_GRID_STYLE, gridTemplateColumns: "1fr 1fr" }}>
          <Form.Item
            label="Rule label"
            name="description"
            rules={[{ required: true, message: "Give the rule a label" }]}
            className="dms_zone_redirect_rule_description_field"
          >
            <Input placeholder="Redirect old campaign page" />
          </Form.Item>
          <Form.Item
            label="Redirect to"
            name="target_url"
            rules={[{ required: true, message: "Enter the destination URL" }]}
            className="dms_zone_redirect_rule_target_field"
          >
            <Input placeholder="https://new.example.com" />
          </Form.Item>
        </div>
        <Form.Item
          label="When the request matches"
          name="expression"
          rules={[{ required: true, message: "Complete the conditions" }]}
          className="dms_zone_redirect_rule_expression_field"
        >
          <ExpressionBuilder />
        </Form.Item>
        <div style={{ ...FORM_GRID_STYLE, gridTemplateColumns: "120px 180px" }}>
          <Form.Item label="Status code" name="status_code" className="dms_zone_redirect_rule_status_field">
            <InputNumber min={301} max={302} style={{ width: "100%" }} />
          </Form.Item>
          <Form.Item label="Query string" name="preserve_query_string" valuePropName="checked" className="dms_zone_redirect_rule_preserve_qs_field">
            <Switch checkedChildren="Keep query" unCheckedChildren="Drop query" />
          </Form.Item>
        </div>
        <Button type="primary" htmlType="submit" className="dms_zone_redirect_rule_add_btn">
          Add redirect rule
        </Button>
      </Form>
      <Table<CloudflareRedirectRule>
        size="small"
        rowKey="id"
        loading={isLoadingRules}
        dataSource={redirectRules}
        columns={redirectRuleColumns}
        pagination={false}
        className="dms_zone_redirect_rules_table"
        locale={{ emptyText: "No edge redirect rules on this zone yet." }}
      />
    </div>
  );

  return (
    <>
      <Modal
        title={account ? `Zone Management - ${account.label}` : "Zone Management"}
        open={open}
        onCancel={onClose}
        footer={null}
        width={900}
        className="dms_zone_security_modal"
        destroyOnHidden
      >
        <Form.Item label="Zone" layout="vertical" className="dms_zone_security_zone_select_field" style={{ marginBottom: 16 }}>
          <Select
            placeholder="Choose a zone"
            loading={isLoadingZones}
            value={zoneId}
            onChange={setZoneId}
            options={zones.map((z) => ({ value: z.id, label: z.name }))}
            className="dms_zone_security_zone_select"
          />
        </Form.Item>

        {zoneId && (
          <Tabs
            size="small"
            items={[
              { key: "dns", label: "DNS Records", children: dnsTab },
              { key: "page_rules", label: "Page Rules", children: pageRulesTab },
              { key: "security", label: "Security Rules", children: securityTab },
              { key: "redirects", label: "Redirects", children: redirectsTab },
            ]}
          />
        )}
      </Modal>

      <Modal
        title={quickRule ? `Quick Add - ${quickRule.label}` : "Quick Add"}
        open={!!quickRule}
        onCancel={() => setQuickRule(null)}
        onOk={() => quickForm.submit()}
        okText="Add rule"
        destroyOnHidden
        className="dms_zone_security_quick_modal"
      >
        {quickRule && (
          <Form<QuickRuleFormValues> form={quickForm} layout="vertical" onFinish={handleQuickRule}>
            <Form.Item
              label={quickRule.valueLabel}
              name="values"
              rules={[{ required: true, type: "array", min: 1, message: "Add at least one value" }]}
              extra={quickRule.field === "ip" ? "Several are fine - press Enter after each. Ranges like 203.0.113.0/24 work too." : undefined}
            >
              {quickRule.field === "country" ? (
                <Select mode="multiple" showSearch optionFilterProp="label" placeholder={quickRule.placeholder} options={COUNTRY_OPTIONS} />
              ) : quickRule.field === "ip" ? (
                <Select mode="tags" tokenSeparators={[",", " "]} placeholder={quickRule.placeholder} open={false} />
              ) : (
                <Select mode="tags" maxCount={1} placeholder={quickRule.placeholder} open={false} />
              )}
            </Form.Item>
            <Form.Item label="Rule label (optional)" name="description" extra="Leave blank to use a label built from the action and value.">
              <Input placeholder={`${quickRule.label}: ...`} />
            </Form.Item>
          </Form>
        )}
      </Modal>
    </>
  );
}
