"use client";

/**
 * The pieces a round of deletion is drawn from.
 *
 * Presentational only — every one of these takes what it renders and reports clicks
 * upward. The panel owns the data and the actions, so there is one fetch and one
 * place where "what happens when you press send" is decided.
 *
 * The shape follows the question being asked. Someone opening this tab wants to know
 * what state the account is in and what is about to happen to it, which is why the
 * strip comes first and reads as a sentence; the emails are two things with two
 * outcomes, so they are two cards rather than rows in a table that was too dense to
 * read.
 */

import {
  Badge,
  Button,
  Card,
  Group,
  Paper,
  Progress,
  SimpleGrid,
  Stack,
  Text,
  Tooltip,
} from "@mantine/core";
import {
  IconAlertTriangle,
  IconClock,
  IconMailForward,
  IconRotateClockwise,
  IconUserOff,
} from "@tabler/icons-react";
import type {
  DeletionRecord,
  EdmStatus,
} from "@/lib/features/account-deletion/query";

export const REGION_LABEL: Record<string, string> = {
  uk: "UK",
  europe: "Europe",
  india: "India",
  indonesia: "Indonesia",
  others: "Rest of world",
};

/*
 * Colour carries meaning here, so the five states stay distinct.
 *
 * `skipped` (could not be sent) and `cancelled` (should not be sent) are different
 * facts, and a shared colour would bury whichever is rarer.
 */
export const EDM_TONE: Record<EdmStatus, string> = {
  sent: "green",
  pending: "gray",
  skipped: "yellow",
  cancelled: "blue",
  failed: "red",
};

export const formatWhen = (value: string | null): string => {
  if (!value) return "—";
  const parsed = new Date(value);
  return Number.isFinite(parsed.getTime()) ? parsed.toLocaleString() : "—";
};

export const formatDay = (value: string | null): string => {
  if (!value) return "—";
  const parsed = new Date(value);
  return Number.isFinite(parsed.getTime()) ? parsed.toLocaleDateString() : "—";
};

/**
 * Whole days until the follow-up.
 *
 * Rounded up: a mail due in eleven hours is "1 day", because rounding to 0 reads as
 * "today" and someone will act on that.
 */
export const daysUntil = (iso: string | null): number | null => {
  if (!iso) return null;
  const due = new Date(iso).getTime();
  if (!Number.isFinite(due)) return null;
  return Math.max(0, Math.ceil((due - Date.now()) / (24 * 60 * 60 * 1000)));
};

export interface RoundActions {
  onSend: (record: DeletionRecord, kind: "notice" | "followup") => void;
  onReactivate: (record: DeletionRecord) => void;
  /** `${recordID}:${kind}` while that one send is in flight. */
  sending: string | null;
}

/**
 * What is happening to this account, in one line and one bar.
 *
 * The bar is elapsed-against-promised rather than a countdown alone: "12 days left"
 * says nothing about whether that is nearly over or barely begun, and the window is
 * configurable now, so the reader cannot assume 30.
 */
export const DeletionStatusStrip: React.FC<{
  accountName: string | null;
  accountNumber: string;
  currentStatus: string | null;
  region: string | null;
  record: DeletionRecord | null;
  memberCount: number;
  activeSessions: number;
  chargeCentre: string | null;
  actionLabel: string;
  onAction: () => void;
  actions: RoundActions;
}> = ({
  accountName,
  accountNumber,
  currentStatus,
  region,
  record,
  memberCount,
  activeSessions,
  chargeCentre,
  actionLabel,
  onAction,
  actions,
}) => {
  const retired = Boolean(record && !record.reactivatedAt);
  const remaining =
    retired && record?.followupEdmStatus === "pending"
      ? daysUntil(record.followupDueAt)
      : null;
  const window = record?.followupDays ?? null;
  const elapsed =
    remaining !== null && window !== null ? Math.max(0, window - remaining) : null;

  return (
    <Card withBorder radius="md" p="lg">
      <Group justify="space-between" align="flex-start" wrap="nowrap">
        <Stack gap={10} style={{ minWidth: 0 }}>
          <Group gap="xs">
            <Badge
              size="lg"
              color={retired ? "red" : record ? "green" : "gray"}
              variant="filled"
              leftSection={
                retired ? <IconUserOff size={13} /> : <IconRotateClockwise size={13} />
              }
            >
              {retired ? "Retired" : record ? "Reactivated" : "Active"}
            </Badge>
            <Text fw={600} fz="lg">
              {currentStatus ?? "—"}
            </Text>
          </Group>

          <Text size="sm" c="dimmed">
            {accountName ?? "—"} · {accountNumber}
            {region ? ` · ${REGION_LABEL[region] ?? region}` : ""}
          </Text>

          <Text size="xs" c="dimmed">
            {memberCount} member{memberCount === 1 ? "" : "s"} · {activeSessions}{" "}
            active session{activeSessions === 1 ? "" : "s"}
            {chargeCentre ? ` · ${chargeCentre}` : ""}
          </Text>
        </Stack>

        <Stack gap={8} align="flex-end" style={{ flexShrink: 0 }}>
          <Button
            color={retired ? "gray" : "red"}
            variant={retired ? "default" : "filled"}
            leftSection={<IconUserOff size={16} />}
            onClick={onAction}
          >
            {actionLabel}
          </Button>
          {retired && record && (
            <Tooltip
              label="This record does not say what status the account held before, so it cannot be restored automatically."
              disabled={record.canReactivate}
              multiline
              w={280}
            >
              <Button
                variant="light"
                color="green"
                leftSection={<IconRotateClockwise size={16} />}
                disabled={!record.canReactivate}
                onClick={() => actions.onReactivate(record)}
              >
                Reactivate
              </Button>
            </Tooltip>
          )}
        </Stack>
      </Group>

      {remaining !== null && (
        <Stack gap={6} mt="lg">
          <Group gap={6}>
            <IconClock size={15} />
            <Text size="sm" fw={500}>
              Data-deletion email in {remaining} day{remaining === 1 ? "" : "s"}
            </Text>
            <Text size="sm" c="dimmed">
              — {formatDay(record?.followupDueAt ?? null)}
            </Text>
          </Group>
          {elapsed !== null && window !== null && (
            <>
              <Progress
                value={(elapsed / window) * 100}
                color="orange"
                size="sm"
                radius="xl"
              />
              <Text size="xs" c="dimmed">
                Day {elapsed} of {window}. Reactivating the account cancels it.
              </Text>
            </>
          )}
        </Stack>
      )}
    </Card>
  );
};

/**
 * One email, as a card.
 *
 * Was a row in a nested table, which put the status, the date, the template and the
 * addresses on four cramped lines inside a timeline bullet. They are four facts
 * about one thing, so they get one card with room to read.
 */
const EmailCard: React.FC<{
  title: string;
  status: EdmStatus;
  at: string | null;
  error: string | null;
  templateName: string;
  templateID: string | null;
  recipients?: string[];
  due?: string | null;
  actionLabel: string;
  loading: boolean;
  onSend: () => void;
}> = ({
  title,
  status,
  at,
  error,
  templateName,
  templateID,
  recipients,
  due,
  actionLabel,
  loading,
  onSend,
}) => (
  <Paper withBorder radius="md" p="md">
    <Stack gap={8}>
      <Group justify="space-between" align="center">
        <Text size="sm" fw={600}>
          {title}
        </Text>
        <Badge variant="light" color={EDM_TONE[status]}>
          {status}
        </Badge>
      </Group>

      <Text size="xs" c="dimmed">
        {status === "pending" && due
          ? `Due ${formatDay(due)}`
          : formatWhen(at)}
      </Text>

      <Stack gap={2}>
        <Text size="xs" fw={500}>
          {templateName}
        </Text>
        <Text size="xs" c="dimmed" style={{ wordBreak: "break-all" }}>
          {templateID ?? "—"}
        </Text>
      </Stack>

      {recipients && (
        <Text size="xs" c="dimmed" style={{ wordBreak: "break-word" }}>
          {recipients.length > 0
            ? `To ${recipients.join(", ")}`
            : "No address on file"}
        </Text>
      )}

      {error && (
        <Group gap={4} align="flex-start" wrap="nowrap">
          <IconAlertTriangle size={13} color="var(--mantine-color-orange-6)" />
          <Text size="xs" c="orange">
            {error}
          </Text>
        </Group>
      )}

      <Button
        size="compact-sm"
        variant="light"
        leftSection={<IconMailForward size={13} />}
        loading={loading}
        onClick={onSend}
        mt={4}
      >
        {actionLabel}
      </Button>
    </Stack>
  </Paper>
);

/** The round's two emails, side by side. */
export const RoundEmails: React.FC<{
  record: DeletionRecord;
  templateLabel: (id: string | null | undefined) => string;
  actions: RoundActions;
}> = ({ record, templateLabel, actions }) => (
  <SimpleGrid cols={{ base: 1, md: 2 }} spacing="md">
    <EmailCard
      title="Acknowledgement"
      status={record.noticeEdmStatus}
      at={record.noticeEdmAt}
      error={record.noticeEdmError}
      templateName={templateLabel(record.noticeTemplateID)}
      templateID={record.noticeTemplateID ?? null}
      recipients={record.recipients}
      actionLabel={
        record.noticeEdmStatus === "sent" ? "Resend" : "Send now"
      }
      loading={actions.sending === `${record.id}:notice`}
      onSend={() => actions.onSend(record, "notice")}
    />
    <EmailCard
      title="Data-deletion confirmation"
      status={record.followupEdmStatus}
      at={record.followupEdmAt}
      error={record.followupEdmError}
      templateName={templateLabel(record.followupTemplateID)}
      templateID={record.followupTemplateID ?? null}
      due={record.followupDueAt}
      actionLabel={
        record.followupEdmStatus === "pending" ? "Send now" : "Resend"
      }
      loading={actions.sending === `${record.id}:followup`}
      onSend={() => actions.onSend(record, "followup")}
    />
  </SimpleGrid>
);

/** The round's own facts: who, why, and what it changed. */
export const RoundFacts: React.FC<{ record: DeletionRecord }> = ({ record }) => (
  <Stack gap={4}>
    <Text size="sm">
      <Text span c="dimmed">
        {record.previousStatus ?? "—"}
      </Text>{" "}
      → <Text span fw={600}>{record.statusName}</Text>
    </Text>
    <Text size="xs" c="dimmed">
      {formatWhen(record.createdAt)} · {record.performedBy ?? "—"}
    </Text>
    <Text size="xs">Reason: {record.reason}</Text>
    <Text size="xs" c="dimmed">
      {record.membersUpdated} member{record.membersUpdated === 1 ? "" : "s"}
      {record.killLogin ? ", login disabled" : ""}
      {record.sessionsRevoked
        ? `, ${record.sessionsRevoked} session${record.sessionsRevoked === 1 ? "" : "s"} dropped`
        : ""}
      {record.softDelete ? ", hidden from lists" : ""}
    </Text>
    {record.reactivatedAt && (
      <Text size="xs" c="green">
        Reactivated {formatWhen(record.reactivatedAt)} by{" "}
        {record.reactivatedBy ?? "—"} · restored to{" "}
        {record.reactivatedToStatus ?? "—"}
      </Text>
    )}
    {record.viewpointLogStatus === "failed" && (
      <Text size="xs" c="orange">
        Viewpoint log note was not written: {record.viewpointLogError}
      </Text>
    )}
    {record.localError && (
      <Text size="xs" c="orange">
        Viewpoint was updated but the member database was not: {record.localError}
      </Text>
    )}
  </Stack>
);
