"use client";

/**
 * The two things about deletion emails that are not per-account.
 *
 * The follow-up window is console-wide policy — it decides what every member is told
 * about when their data will be erased — and the test send proves the SendGrid path
 * works without involving a real member. Neither belongs on a deletion record, so
 * they sit together above the history rather than inside it.
 *
 * Super admin only, enforced by core on both endpoints. The panel that renders this
 * is itself only shown to super admins.
 */

import {
  Alert,
  Button,
  Card,
  Collapse,
  Group,
  NumberInput,
  Select,
  Stack,
  Text,
  TextInput,
} from "@mantine/core";
import { notifications } from "@mantine/notifications";
import {
  IconChevronDown,
  IconChevronUp,
  IconClock,
  IconMailForward,
  IconSettings,
} from "@tabler/icons-react";
import { useEffect, useState } from "react";
import {
  saveDeletionConfig,
  sendTestDeletionMail,
  type DeletionConfig,
  type DeletionRegion,
} from "@/lib/features/account-deletion/query";
import styles from "@/routes/promo-code-campaigns/_components/promo.module.css";

const DeletionSettingsCard: React.FC<{
  config: DeletionConfig | null;
  /** The account being looked at, so a test letter reads like a real one. */
  accountNumber?: string;
  accountName?: string | null;
  /**
   * The account's region, so the test offers the letters it would actually get.
   *
   * Testing a template this account would never be sent proves nothing about this
   * account, so the picker is narrowed to its own pair rather than the whole
   * catalogue.
   */
  region?: DeletionRegion;
  /** Called after the window is saved, so the panel can show the new figure. */
  onConfigSaved?: (followupDays: number) => void;
}> = ({ config, accountNumber, accountName, region, onConfigSaved }) => {
  const [open, setOpen] = useState(false);

  const [days, setDays] = useState<number | string>(config?.followupDays ?? 30);
  const [savingDays, setSavingDays] = useState(false);

  const [testTemplate, setTestTemplate] = useState<string | null>(null);
  const [testEmail, setTestEmail] = useState("");
  const [sendingTest, setSendingTest] = useState(false);

  // Seeded from the fetched setting rather than defaulted to 30 forever: the input
  // has to show what is currently in force before anyone changes it.
  useEffect(() => {
    if (config?.followupDays) setDays(config.followupDays);
  }, [config?.followupDays]);

  /*
   * The two letters this account would actually be sent.
   *
   * Narrowed from the catalogue to the account's own region and preselected, because
   * the question being asked is "does this account's letter work" — offering ten
   * templates and no default made the operator pick, and picking the wrong one
   * proves nothing about this member.
   */
  const regionEntry =
    config?.regions.find((entry) => entry.region === region) ?? null;

  const templateOptions = regionEntry
    ? [
        {
          value: regionEntry.acknowledgement.id,
          label: `Acknowledgement — ${regionEntry.acknowledgement.name}`,
        },
        {
          value: regionEntry.confirmation.id,
          label: `Data-deletion confirmation — ${regionEntry.confirmation.name}`,
        },
      ]
    : [];

  // Preselected once the catalogue arrives, and re-seeded if the region changes.
  useEffect(() => {
    if (regionEntry) setTestTemplate(regionEntry.acknowledgement.id);
  }, [regionEntry?.acknowledgement.id]);

  const saveDays = async () => {
    const parsed = Number(days);
    if (!Number.isFinite(parsed) || parsed < 1 || parsed > 365) {
      notifications.show({
        color: "red",
        message: "The window must be between 1 and 365 days",
      });
      return;
    }
    setSavingDays(true);
    const response = await saveDeletionConfig(parsed);
    setSavingDays(false);

    if (!response.success || !response.data) {
      notifications.show({
        color: "red",
        message: response.message || "Failed to save the window",
      });
      return;
    }
    // Echo what core stored, not what was typed — it clamps, and showing the typed
    // figure would misreport what deletions will actually use.
    setDays(response.data.followupDays);
    onConfigSaved?.(response.data.followupDays);
    notifications.show({ color: "green", message: response.message });
  };

  /*
   * Several addresses from one field, split on commas, semicolons and whitespace.
   *
   * A test usually goes to the operator and whoever asked for it, and pasting a
   * short list is how people actually do that — a single-address field turned it
   * into three submissions and three chances to pick the wrong template.
   */
  const addresses = testEmail
    .split(/[,;\s]+/)
    .map((value) => value.trim())
    .filter(Boolean);

  const invalidAddresses = addresses.filter(
    (address) => !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(address),
  );

  const sendTest = async () => {
    if (!testTemplate || addresses.length === 0 || invalidAddresses.length) {
      return;
    }
    setSendingTest(true);
    const response = await sendTestDeletionMail({
      templateID: testTemplate,
      to: addresses,
      accountNumber,
      accountName: accountName ?? undefined,
    });
    setSendingTest(false);

    notifications.show({
      color: response.success ? "green" : "red",
      autoClose: response.success ? 10000 : false,
      message:
        response.message ||
        (response.success ? "Test email queued" : "Failed to queue the test email"),
    });

    // Per-address failures are their own message: the overall call can succeed
    // while one address is refused, and a green toast alone would hide that.
    if (response.data?.failed.length) {
      notifications.show({
        color: "orange",
        autoClose: false,
        title: "Some addresses were not accepted",
        message: response.data.failed
          .map((entry) => `${entry.to}: ${entry.message}`)
          .join(" · "),
      });
    }
  };

  return (
    <Card className={styles.sectionCard} p="md">
      <Group justify="space-between" align="center">
        <Group gap={8} align="center">
          <span className={styles.sectionIcon}>
            <IconSettings size={15} />
          </span>
          <Text fz={14} fw={600}>
            Email settings
          </Text>
          <Text size="xs" c="dimmed">
            Follow-up window: {config?.followupDays ?? 30} days
          </Text>
        </Group>
        <Button
          size="compact-sm"
          variant="subtle"
          rightSection={
            open ? <IconChevronUp size={14} /> : <IconChevronDown size={14} />
          }
          onClick={() => setOpen((value) => !value)}
        >
          {open ? "Hide" : "Configure"}
        </Button>
      </Group>

      <Collapse in={open}>
        <Stack gap="lg" mt="md">
          <Stack gap="xs">
            <Group gap={6}>
              <IconClock size={16} />
              <Text size="sm" fw={600}>
                Data-deletion email window
              </Text>
            </Group>
            <Text size="xs" c="dimmed">
              How long after an account is retired the data-deletion confirmation is
              sent. Console-wide, and it applies to deletions from now on — mail
              already promised keeps the date the member was given, so shortening
              this never pulls a queued letter forward.
            </Text>
            <Group align="flex-end" gap="sm">
              <NumberInput
                label="Days"
                min={1}
                max={365}
                value={days}
                onChange={setDays}
                w={140}
              />
              <Button
                loading={savingDays}
                disabled={Number(days) === config?.followupDays}
                onClick={() => void saveDays()}
              >
                Save
              </Button>
            </Group>
          </Stack>

          <Stack gap="xs">
            <Group gap={6}>
              <IconMailForward size={16} />
              <Text size="sm" fw={600}>
                Send a test letter
              </Text>
            </Group>
            <Text size="xs" c="dimmed">
              Goes onto the same SMTP queue and uses the same template as a real
              send, so it proves the path a member&apos;s letter actually takes.
              Nothing is recorded against any account.
            </Text>
            <Group align="flex-end" gap="sm">
              <Select
                label="Letter"
                description="The letters this account's region would be sent"
                placeholder={
                  regionEntry ? "Pick a letter" : "No region resolved for this account"
                }
                data={templateOptions}
                value={testTemplate}
                onChange={setTestTemplate}
                searchable
                flex={1}
              />
              <TextInput
                label="Send to"
                description="One or more addresses, separated by commas"
                placeholder="you@karmagroup.com, someone@karmagroup.com"
                value={testEmail}
                onChange={(event) => setTestEmail(event.currentTarget.value)}
                error={
                  invalidAddresses.length
                    ? `Not an email address: ${invalidAddresses.join(", ")}`
                    : null
                }
                flex={1}
              />
              <Button
                loading={sendingTest}
                disabled={
                  !testTemplate ||
                  addresses.length === 0 ||
                  invalidAddresses.length > 0
                }
                onClick={() => void sendTest()}
              >
                Send test
                {addresses.length > 1 ? ` (${addresses.length})` : ""}
              </Button>
            </Group>
            <Alert color="gray" variant="light" p={8}>
              <Text size="xs">
                A green result means the message reached the queue, not the inbox.
                Delivery is the SMTP worker&apos;s and SendGrid&apos;s — if nothing
                arrives, the queue is the first place to look, then SendGrid&apos;s
                activity feed for that template.
              </Text>
            </Alert>
          </Stack>
        </Stack>
      </Collapse>
    </Card>
  );
};

export default DeletionSettingsCard;
