"use client";

import type { Domain } from "@domainops/shared-types";
import { App, Button, Form, Input, Modal, Progress, Select, Switch, Table, Tag } from "antd";
import { useCallback, useEffect, useRef, useState } from "react";
import { listDomains } from "@/lib/api/domains";
import { createRedirect } from "@/lib/api/redirects";
import { ApiError } from "@/lib/api/client";

interface BulkFormValues {
  sources: { value: number; label: string }[];
  target_url: string;
  type: "301" | "302";
  preserve_path: boolean;
}

interface DomainOption {
  value: number;
  label: string;
  disabled: boolean;
}

interface ResultRow {
  id: number;
  fqdn: string;
  status: "done" | "failed";
  message: string;
}

const DESTINATION_PATTERN = new RegExp("^(https?://)?[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)+(/\\S*)?$");

const TYPE_OPTIONS = [
  { value: "301", label: "301 (Permanent)" },
  { value: "302", label: "302 (Temporary)" },
];

function toOptions(domains: Domain[]): DomainOption[] {
  return domains.flatMap((domain) => [domain, ...(domain.subdomains ?? [])]).map((domain) => {
    const hasRedirect = !!domain.redirect_event;
    const base = domain.cf_zone_id ? domain.fqdn : `${domain.fqdn} (no Cloudflare)`;

    return {
      value: domain.id,
      label: hasRedirect ? `${base} (has a redirect - will be replaced)` : base,
      disabled: !domain.cf_zone_id,
    };
  });
}

/**
 * Points several domains at one destination in a single pass. Each source
 * goes through the same endpoint as a single redirect, one after another, so
 * a Cloudflare rule-limit or any other failure on one domain is reported on
 * its own row and never stops the rest.
 */
export function BulkRedirectModal({
  open,
  onClose,
  onDone,
}: {
  open: boolean;
  onClose: () => void;
  onDone: () => void;
}) {
  const { modal } = App.useApp();
  const [form] = Form.useForm<BulkFormValues>();
  const [options, setOptions] = useState<DomainOption[]>([]);
  const [isSearching, setIsSearching] = useState(false);
  const [isRunning, setIsRunning] = useState(false);
  const [results, setResults] = useState<ResultRow[]>([]);
  const [total, setTotal] = useState(0);
  const searchTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  const search = useCallback(async (term: string) => {
    setIsSearching(true);
    try {
      const result = await listDomains({ search: term, page: 1 });
      setOptions(toOptions(result.data));
    } finally {
      setIsSearching(false);
    }
  }, []);

  useEffect(() => {
    if (!open) return;
    form.resetFields();
    // eslint-disable-next-line react-hooks/set-state-in-effect
    setResults([]);
    setTotal(0);
    void search("");
  }, [open, form, search]);

  function handleSearch(term: string) {
    if (searchTimer.current) clearTimeout(searchTimer.current);
    searchTimer.current = setTimeout(() => void search(term), 300);
  }

  async function run(values: BulkFormValues) {
    setIsRunning(true);
    setResults([]);
    setTotal(values.sources.length);

    let anyDone = false;
    for (const source of values.sources) {
      const fqdn = source.label.replace(/ \(.*\)$/, "");
      try {
        await createRedirect(source.value, {
          target_url: values.target_url,
          type: values.type,
          preserve_path: values.preserve_path,
        });
        anyDone = true;
        setResults((rows) => [...rows, { id: source.value, fqdn, status: "done", message: "Redirect created." }]);
      } catch (err) {
        const reason = err instanceof ApiError ? (err.errors?.rule_limit ? "Cloudflare redirect rules are full." : err.message) : "Couldn't create that redirect.";
        setResults((rows) => [...rows, { id: source.value, fqdn, status: "failed", message: reason }]);
      }
    }

    setIsRunning(false);
    if (anyDone) onDone();
  }

  function handleFinish(values: BulkFormValues) {
    const target = values.target_url.replace(/^https?:\/\//, "");
    modal.confirm({
      title: `Redirect ${values.sources.length} domain${values.sources.length === 1 ? "" : "s"} to ${target}?`,
      content: "Each domain gets a Cloudflare redirect rule. A domain that already has a redirect will have it replaced.",
      okText: "Create redirects",
      onOk: () => run(values),
    });
  }

  const doneCount = results.filter((r) => r.status === "done").length;
  const failedCount = results.length - doneCount;
  const hasRun = total > 0;

  return (
    <Modal
      title="Bulk Add Redirects"
      open={open}
      onCancel={isRunning ? undefined : onClose}
      closable={!isRunning}
      mask={{ closable: false }}
      destroyOnHidden
      width={680}
      className="dms_bulk_redirect_modal"
      footer={[
        <Button key="close" onClick={onClose} disabled={isRunning} className="dms_bulk_redirect_close_button">
          Close
        </Button>,
        <Button
          key="create"
          type="primary"
          loading={isRunning}
          onClick={() => form.submit()}
          className="dms_bulk_redirect_create_button"
        >
          Create redirects
        </Button>,
      ]}
    >
      <Form<BulkFormValues>
        form={form}
        layout="vertical"
        requiredMark
        onFinish={handleFinish}
        disabled={isRunning}
        initialValues={{ type: "301", preserve_path: true }}
        className="dms_bulk_redirect_form"
      >
        <Form.Item
          name="sources"
          label="Domains to redirect"
          rules={[{ required: true, type: "array", min: 1, message: "Pick at least one domain" }]}
          extra="Domains and subdomains from Domain Inventory. Only domains already on Cloudflare can be picked."
          className="dms_bulk_redirect_sources_field"
        >
          <Select<{ value: number; label: string }[]>
            mode="multiple"
            labelInValue
            showSearch
            filterOption={false}
            loading={isSearching}
            options={options}
            onSearch={handleSearch}
            placeholder="Search and pick several domains"
            maxTagCount="responsive"
          />
        </Form.Item>
        <Form.Item
          name="target_url"
          label="Redirect all of them to"
          rules={[
            { required: true, message: "Enter the destination domain" },
            { pattern: DESTINATION_PATTERN, message: "Enter a domain like newsite.com" },
          ]}
          extra="One destination for every domain above - just the domain, https:// is added automatically."
          className="dms_bulk_redirect_target_field"
        >
          <Input placeholder="newsite.com" />
        </Form.Item>
        <div className="grid grid-cols-1 sm:grid-cols-2 gap-x-4">
          <Form.Item name="type" label="Type" className="dms_bulk_redirect_type_field">
            <Select options={TYPE_OPTIONS} />
          </Form.Item>
          <Form.Item
            name="preserve_path"
            label="Keep the page path"
            valuePropName="checked"
            extra="On: /about goes to /about on the target. Off: every page goes to its home page."
            className="dms_bulk_redirect_preserve_path_field"
          >
            <Switch />
          </Form.Item>
        </div>
      </Form>

      {hasRun && (
        <div className="flex flex-col gap-3 mt-2 dms_bulk_redirect_results">
          <Progress percent={Math.round((results.length / total) * 100)} status={isRunning ? "active" : failedCount > 0 ? "exception" : "success"} />
          <p className="text-sm">
            {doneCount} created{failedCount > 0 ? `, ${failedCount} failed` : ""} of {total}.
          </p>
          <Table<ResultRow>
            size="small"
            rowKey="id"
            pagination={false}
            dataSource={results}
            scroll={{ y: 220 }}
            columns={[
              { title: "Domain", dataIndex: "fqdn", render: (v: string) => <span className="font-mono">{v}</span> },
              {
                title: "Result",
                dataIndex: "status",
                width: 110,
                render: (v: ResultRow["status"]) => (v === "done" ? <Tag color="green">Done</Tag> : <Tag color="red">Failed</Tag>),
              },
              { title: "Detail", dataIndex: "message" },
            ]}
            className="dms_bulk_redirect_results_table"
          />
        </div>
      )}
    </Modal>
  );
}
