"use client";

import type { CloudflareSecurityAction } from "@domainops/shared-types";
import { App, Button, Form, Modal, Select } from "antd";
import { PlusOutlined, WarningOutlined } from "@ant-design/icons";
import { useState } from "react";
import { ApiError } from "@/lib/api/client";
import { COUNTRY_OPTIONS } from "@/lib/utils/countries";
import { conditionToExpression } from "@/lib/utils/cfExpression";

export interface PresetRule {
  description: string;
  expression: string;
  action: CloudflareSecurityAction;
}

interface InstantPreset {
  key: string;
  label: string;
  warn?: boolean;
  rule: PresetRule;
}

interface AskedPreset {
  key: string;
  label: string;
  warn?: boolean;
  kind: "ip" | "country";
  prompt: string;
  build: (values: string[]) => PresetRule | null;
}

const BAD_BOT_AGENTS = ["AhrefsBot", "SemrushBot", "MJ12bot", "DotBot", "python-requests", "Scrapy", "curl", "GPTBot", "CCBot", "ClaudeBot", "Bytespider"];

const INSTANT_PRESETS: InstantPreset[] = [
  {
    key: "allow_bots",
    label: "Allow bots & DMCA",
    rule: {
      description: "Allow verified bots and DMCA agents",
      expression: '(cf.client.bot) or (http.user_agent contains "DMCA")',
      action: "allow",
    },
  },
  {
    key: "block_bots",
    label: "Block bots & scrapers",
    rule: {
      description: "Block bots and scrapers",
      expression: BAD_BOT_AGENTS.map((agent) => `(http.user_agent contains "${agent}")`).join(" or "),
      action: "block",
    },
  },
  {
    key: "block_wplogin",
    label: "Block wp-login",
    rule: {
      description: "Block wp-login.php",
      expression: '(http.request.uri.path contains "/wp-login.php")',
      action: "block",
    },
  },
  {
    key: "challenge_suspicious",
    label: "Challenge suspicious",
    warn: true,
    rule: {
      description: "Challenge suspicious visitors",
      expression: "(cf.threat_score gt 14)",
      action: "challenge",
    },
  },
];

const ASKED_PRESETS: AskedPreset[] = [
  {
    key: "allow_ip",
    label: "Allow IP",
    kind: "ip",
    prompt: "IP addresses to allow",
    build: (values) => {
      const expression = conditionToExpression({ field: "ip", operator: values.length > 1 ? "in" : "eq", values, join: "and" });

      return expression ? { description: `Allow IP ${values.join(", ")}`, expression, action: "allow" } : null;
    },
  },
  {
    key: "block_ip",
    label: "Block IP",
    kind: "ip",
    prompt: "IP addresses to block",
    build: (values) => {
      const expression = conditionToExpression({ field: "ip", operator: values.length > 1 ? "in" : "eq", values, join: "and" });

      return expression ? { description: `Block IP ${values.join(", ")}`, expression, action: "block" } : null;
    },
  },
  {
    key: "block_region",
    label: "Block region",
    kind: "country",
    prompt: "Countries to block",
    build: (values) => {
      const expression = conditionToExpression({ field: "country", operator: values.length > 1 ? "in" : "eq", values, join: "and" });

      return expression ? { description: `Block region ${values.join(", ")}`, expression, action: "block" } : null;
    },
  },
  {
    key: "allow_region_only",
    label: "Allow region only",
    warn: true,
    kind: "country",
    prompt: "Only these countries can visit - everyone else is blocked",
    build: (values) => {
      const expression = conditionToExpression({ field: "country", operator: "not_in", values, join: "and" });

      return expression ? { description: `Allow ${values.join(", ")} only`, expression, action: "block" } : null;
    },
  },
];

/**
 * One-click quick presets for a zone's security rules: some add a rule
 * straight away, the ones that need a value (an IP, a country) ask for it
 * first. The warning-coloured ones can lock real visitors out, so they ask
 * for confirmation. The caller creates the rule, so the same row works for a
 * domain's own zone and for any account zone.
 */
export function SecurityPresets({ onCreate }: { onCreate: (rule: PresetRule) => Promise<void> }) {
  const { message, modal } = App.useApp();
  const [asked, setAsked] = useState<AskedPreset | null>(null);
  const [isBusy, setIsBusy] = useState(false);
  const [form] = Form.useForm<{ values: string[] }>();

  async function create(rule: PresetRule) {
    setIsBusy(true);
    try {
      await onCreate(rule);
    } catch (err) {
      message.error(err instanceof ApiError ? err.message : "Couldn't add that rule.");
    } finally {
      setIsBusy(false);
    }
  }

  function handleInstant(preset: InstantPreset) {
    if (!preset.warn) {
      void create(preset.rule);

      return;
    }

    modal.confirm({
      title: `Add "${preset.label}"?`,
      content: "This can challenge or block real visitors. Check the rule list afterwards.",
      okText: "Add rule",
      onOk: () => create(preset.rule),
    });
  }

  async function handleAsked(values: { values: string[] }) {
    if (!asked) return;
    const rule = asked.build(values.values);

    if (!rule) {
      message.error(asked.kind === "ip" ? "Enter valid IP addresses, for example 203.0.113.10 or 203.0.113.0/24." : "Check the countries you picked.");

      return;
    }

    const run = async () => {
      await create(rule);
      setAsked(null);
      form.resetFields();
    };

    if (asked.warn) {
      modal.confirm({
        title: `Add "${asked.label}"?`,
        content: "Visitors from anywhere else will be blocked, including you if you are travelling.",
        okText: "Add rule",
        onOk: run,
      });

      return;
    }

    await run();
  }

  const chip = (key: string, label: string, warn: boolean | undefined, onClick: () => void) => (
    <Button
      key={key}
      size="small"
      shape="round"
      icon={warn ? <WarningOutlined /> : <PlusOutlined />}
      disabled={isBusy}
      onClick={onClick}
      className={`dms_security_preset_btn${warn ? " dms_security_preset_btn--warn" : ""}`}
    >
      {label}
    </Button>
  );

  return (
    <div className="dms_security_presets">
      <div className="text-xs text-gray-500 mb-2">Quick presets - add with one click:</div>
      <div className="flex flex-wrap gap-2">
        {INSTANT_PRESETS.slice(0, 3).map((p) => chip(p.key, p.label, p.warn, () => handleInstant(p)))}
        {ASKED_PRESETS.slice(0, 2).map((p) => chip(p.key, p.label, p.warn, () => setAsked(p)))}
        {ASKED_PRESETS.slice(2).map((p) => chip(p.key, p.label, p.warn, () => setAsked(p)))}
        {INSTANT_PRESETS.slice(3).map((p) => chip(p.key, p.label, p.warn, () => handleInstant(p)))}
      </div>

      <Modal
        open={!!asked}
        title={asked?.label}
        onCancel={() => setAsked(null)}
        onOk={() => form.submit()}
        okText="Add rule"
        confirmLoading={isBusy}
        mask={{ closable: false }}
        destroyOnHidden
        className="dms_security_preset_modal"
      >
        <Form form={form} layout="vertical" onFinish={handleAsked}>
          <Form.Item name="values" label={asked?.prompt} rules={[{ required: true, message: "Add at least one value" }]}>
            {asked?.kind === "country" ? (
              <Select mode="multiple" showSearch optionFilterProp="label" options={COUNTRY_OPTIONS} placeholder="Pick countries" />
            ) : (
              <Select mode="tags" tokenSeparators={[",", " "]} open={false} placeholder="203.0.113.10, 203.0.113.0/24" />
            )}
          </Form.Item>
        </Form>
      </Modal>
    </div>
  );
}
