import { useMemo } from "react";
import type { ApiSettings } from "../../types";
import Button from "../../components/Button";
import Card from "../../components/Card";
import FormField from "../../components/FormField";
import PageTitle from "../../components/PageTitle";
import LoadingFrame from "../../components/LoadingFrame";
import LockedVersionNotice from "./components/LockedVersionNotice";
import VersionLine from "./components/VersionLine";
import ToggleSwitch from "../../components/ToggleSwitch";
import EmailAddressInput from "../../components/email/EmailAddressInput";
import DismissibleAlert from "../../components/DismissibleAlert";
import DataGrid, { DataGridEmptyAction, DataGridRowActions, type DataGridColumn } from "../../components/table/DataGrid";
import { useCampaignWorkspaceData } from "./hooks/useCampaignWorkspaceData";
import { useCampaignDraftEditor } from "./hooks/useCampaignDraftEditor";
import { asArray, asRecord, isAuditLockedVersion } from "./utils/campaignView";
import { getBool } from "./utils/draftEditor";
import {
  addressesFromValue,
  collectCampaignAddressSuggestions,
  type MailboxAddress
} from "../../utils/emailAddresses";
import { insertAfter, moveArrayItem } from "../../utils/arrayOrder";

const recipientHeaderRows = [
  { key: "to", label: "To", toggleKey: "allow_individual_to", toggleLabel: "Allow individual To", addLabel: "Add recipient", emptyText: "No global recipients configured." },
  { key: "cc", label: "CC", toggleKey: "allow_individual_cc", toggleLabel: "Allow individual CC", addLabel: "Add CC", emptyText: "No global CC recipients configured." },
  { key: "bcc", label: "BCC", toggleKey: "allow_individual_bcc", toggleLabel: "Allow individual BCC", addLabel: "Add BCC", emptyText: "No global BCC recipients configured." }
] as const;

type RecipientAddressKey = "to" | "cc" | "bcc";

type EntryAddressColumn = {
  key: RecipientAddressKey | "from" | "reply_to";
  label: string;
  allowMultiple: boolean;
  addLabel: string;
  emptyText: string;
};

export default function RecipientDataPage({ settings, campaignId }: { settings: ApiSettings; campaignId: string }) {
  const { data, loading, error, reload, setError } = useCampaignWorkspaceData(settings, campaignId);

  const version = data.currentVersion;
  const locked = isAuditLockedVersion(version, data.campaign?.current_version_id);
  const { draft, displayDraft, dirty, saveState, localError, patch, saveDraft } = useCampaignDraftEditor({
    settings,
    campaignId,
    version,
    locked,
    reload,
    setError,
    currentStep: "recipients",
    unsavedTitle: "Unsaved recipient changes",
    unsavedMessage: "Recipient address data has unsaved changes. Save it before leaving, or discard it and continue."
  });
  const recipientsSection = asRecord(displayDraft.recipients);
  const entries = asRecord(displayDraft.entries);
  const inlineEntries = asArray(entries.inline).map(asRecord);
  const source = asRecord(entries.source);
  const addressSuggestions = useMemo(() => collectCampaignAddressSuggestions(displayDraft), [displayDraft]);
  const defaultFrom = addressesFromValue(recipientsSection.from);
  const globalReplyTo = addressesFromValue(recipientsSection.reply_to);
  const globalRecipientValues: Record<string, MailboxAddress[]> = {
    to: addressesFromValue(recipientsSection.to),
    cc: addressesFromValue(recipientsSection.cc),
    bcc: addressesFromValue(recipientsSection.bcc)
  };
  const entryAddressColumns = useMemo<EntryAddressColumn[]>(() => {
    const columns: EntryAddressColumn[] = [{ key: "to", label: "To", allowMultiple: true, addLabel: "Add To", emptyText: "No recipient address." }];
    if (getBool(recipientsSection, "allow_individual_cc")) columns.push({ key: "cc", label: "CC", allowMultiple: true, addLabel: "Add CC", emptyText: "No CC." });
    if (getBool(recipientsSection, "allow_individual_bcc")) columns.push({ key: "bcc", label: "BCC", allowMultiple: true, addLabel: "Add BCC", emptyText: "No BCC." });
    if (getBool(recipientsSection, "allow_individual_from")) columns.push({ key: "from", label: "Sender", allowMultiple: false, addLabel: "Set sender", emptyText: "Uses default sender." });
    if (getBool(recipientsSection, "allow_individual_reply_to")) columns.push({ key: "reply_to", label: "Reply-To", allowMultiple: false, addLabel: "Set Reply-To", emptyText: "Uses global Reply-To." });
    return columns;
  }, [recipientsSection]);


  function replaceInlineEntries(nextEntries: Record<string, unknown>[]) {
    patch(["entries", "inline"], nextEntries);
  }

  function addRecipient(afterIndex = inlineEntries.length - 1) {
    const nextIndex = inlineEntries.length + 1;
    const newEntry = {
      id: uniqueEntryId(inlineEntries, `recipient-${nextIndex}`),
      active: true,
      to: [],
      cc: [],
      bcc: [],
      name: "",
      email: "",
      from: {},
      reply_to: []
    };
    replaceInlineEntries(insertAfter(inlineEntries, afterIndex, newEntry));
  }

  function updateEntry(index: number, updater: (entry: Record<string, unknown>) => Record<string, unknown>) {
    const nextEntries = inlineEntries.map((entry, currentIndex) => currentIndex === index ? updater(entry) : entry);
    replaceInlineEntries(nextEntries);
  }

  function updateEntryAddressList(index: number, key: EntryAddressColumn["key"], addresses: MailboxAddress[]) {
    updateEntry(index, (entry) => {
      if (key === "from") {
        return { ...entry, from: addresses[0] ?? { name: "", email: "" } };
      }
      const nextEntry = { ...entry, [key]: key === "reply_to" ? addresses.slice(0, 1) : addresses };
      if (key === "to") {
        const address = addresses[0] ?? { name: "", email: "" };
        return {
          ...nextEntry,
          name: address.name ?? "",
          email: address.email
        };
      }
      return nextEntry;
    });
  }

  function removeEntry(index: number) {
    replaceInlineEntries(inlineEntries.filter((_, currentIndex) => currentIndex !== index));
  }

  function moveEntry(index: number, targetIndex: number) {
    if (locked || index === targetIndex) return;
    replaceInlineEntries(moveArrayItem(inlineEntries, index, targetIndex));
  }


  return (
    <div className="content-pad workspace-data-page">
      <div className="page-heading split workspace-heading">
        <div>
          <PageTitle loading={loading}>Sender & Recipients</PageTitle>
          <VersionLine version={version} versions={data.versions} status={saveState} />
        </div>
        <div className="button-row compact-actions">
          <Button onClick={reload} disabled={loading}>Reload</Button>
          <Button variant="primary" onClick={() => saveDraft("manual")} disabled={!dirty || locked || !draft}>Save</Button>
        </div>
      </div>

      {error && <DismissibleAlert tone="danger" resetKey={error} floating>{error}</DismissibleAlert>}
      {localError && <DismissibleAlert tone="danger" resetKey={localError} floating>{localError}</DismissibleAlert>}
      {locked && <LockedVersionNotice settings={settings} campaignId={campaignId} version={version} currentVersionId={data.campaign?.current_version_id} reload={reload} message="This page is read-only for the selected version." />}

      <LoadingFrame loading={loading || !draft} label="Loading campaign draft…">
        <>
          <Card title="Campaign sender">
            <div className="campaign-header-stack">
              <div className="campaign-header-grid">
                <FormField label="Default From address">
                  <EmailAddressInput
                    value={defaultFrom}
                    suggestions={addressSuggestions}
                    allowMultiple={false}
                    showAddButton={false}
                    disabled={locked}
                    addLabel={defaultFrom.length ? "Replace" : "Add sender"}
                    emptyText="No default sender configured."
                    onChange={(addresses: MailboxAddress[]) => patch(["recipients", "from"], addresses[0] ?? { name: "", email: "" })}
                  />
                </FormField>
                <div className="campaign-header-toggle">
                  <ToggleSwitch
                    label="Allow individual senders"
                    checked={getBool(recipientsSection, "allow_individual_from")}
                    disabled={locked}
                    onChange={(checked) => patch(["recipients", "allow_individual_from"], checked)}
                  />
                </div>
              </div>

              <div className="campaign-header-grid">
                <FormField label="Global Reply-To address">
                  <EmailAddressInput
                    value={globalReplyTo.slice(0, 1)}
                    suggestions={addressSuggestions}
                    allowMultiple={false}
                    showAddButton={false}
                    disabled={locked}
                    addLabel={globalReplyTo.length ? "Replace" : "Add Reply-To"}
                    emptyText="No Reply-To address configured."
                    onChange={(addresses: MailboxAddress[]) => patch(["recipients", "reply_to"], addresses.slice(0, 1))}
                  />
                </FormField>
                <div className="campaign-header-toggle">
                  <ToggleSwitch
                    label="Allow individual Reply-To"
                    checked={getBool(recipientsSection, "allow_individual_reply_to")}
                    disabled={locked}
                    onChange={(checked) => patch(["recipients", "allow_individual_reply_to"], checked)}
                  />
                </div>
              </div>
            </div>
          </Card>

          <Card title="Global recipient headers">
            <div className="campaign-header-stack">
              {recipientHeaderRows.map((row) => (
                <div className="campaign-header-grid" key={row.key}>
                  <FormField label={row.label}>
                    <EmailAddressInput
                      value={globalRecipientValues[row.key] ?? []}
                      suggestions={addressSuggestions}
                      allowMultiple
                      disabled={locked}
                      addLabel={row.addLabel}
                      emptyText={row.emptyText}
                      onChange={(addresses: MailboxAddress[]) => patch(["recipients", row.key], addresses)}
                    />
                  </FormField>
                  <div className="campaign-header-toggle">
                    <ToggleSwitch
                      label={row.toggleLabel}
                      checked={getBool(recipientsSection, row.toggleKey)}
                      disabled={locked}
                      onChange={(checked) => patch(["recipients", row.toggleKey], checked)}
                    />
                  </div>
                </div>
              ))}
            </div>
          </Card>

          <Card
            title="Recipient profiles"
            actions={<Button disabled>Import</Button>}
          >
            {inlineEntries.length === 0 && Boolean(source.type) && (
              <DismissibleAlert tone="info">This campaign references an external recipient source. A parsed preview table will be added when file/source preview support is implemented.</DismissibleAlert>
            )}
            {!source.type && (
              <DataGrid
                id={`campaign-${campaignId}-recipient-profiles`}
                rows={inlineEntries.slice(0, 100)}
                columns={recipientProfileColumns({ locked, entries: inlineEntries, entryAddressColumns, addressSuggestions, updateEntryAddressList, updateEntry, addRecipient, moveEntry, removeEntry })}
                getRowKey={(entry, index) => String(entry.id || index)}
                emptyText="No recipient profiles are stored in the current version yet."
                emptyAction={<DataGridEmptyAction onAdd={() => addRecipient(-1)} disabled={locked} label="Add first recipient" />}
                className="recipient-table-wrap recipient-address-table"
              />
            )}
          </Card>

          <div className="button-row page-bottom-actions">
            <Button variant="primary" onClick={() => saveDraft("manual")} disabled={!dirty || locked}>Save</Button>
          </div>
        </>
      </LoadingFrame>
    </div>
  );
}

type RecipientProfileColumnContext = {
  locked: boolean;
  entries: Record<string, unknown>[];
  entryAddressColumns: EntryAddressColumn[];
  addressSuggestions: MailboxAddress[];
  updateEntryAddressList: (index: number, key: EntryAddressColumn["key"], addresses: MailboxAddress[]) => void;
  updateEntry: (index: number, updater: (entry: Record<string, unknown>) => Record<string, unknown>) => void;
  addRecipient: (afterIndex?: number) => void;
  moveEntry: (index: number, targetIndex: number) => void;
  removeEntry: (index: number) => void;
};

function recipientProfileColumns({ locked, entries, entryAddressColumns, addressSuggestions, updateEntryAddressList, updateEntry, addRecipient, moveEntry, removeEntry }: RecipientProfileColumnContext): DataGridColumn<Record<string, unknown>>[] {
  return [
    { id: "number", header: "#", width: 70, sortable: true, sticky: "start", render: (_entry, index) => <span className="mono-small">{index + 1}</span>, value: (_entry, index) => index + 1 },
    ...entryAddressColumns.map((column): DataGridColumn<Record<string, unknown>> => ({
      id: column.key,
      header: column.label,
      width: column.key === "to" ? "minmax(260px, 1.2fr)" : 250,
      resizable: true,
      filterable: true,
      render: (entry, index) => (
        <EmailAddressInput
          value={getEntryAddresses(entry, column.key)}
          suggestions={addressSuggestions}
          allowMultiple={column.allowMultiple}
          compact
          disabled={locked}
          addLabel={column.addLabel}
          emptyText={column.emptyText}
          onChange={(addresses) => updateEntryAddressList(index, column.key, addresses)}
        />
      ),
      value: (entry) => getEntryAddresses(entry, column.key).map((address) => `${address.name ?? ""} ${address.email ?? ""}`).join(", ")
    })),
    { id: "active", header: "Active", width: 130, sortable: true, filterable: true, render: (entry, index) => <ToggleSwitch label="Active" checked={entry.active !== false} disabled={locked} onChange={(checked) => updateEntry(index, (current) => ({ ...current, active: checked }))} />, value: (entry) => entry.active !== false ? "active" : "inactive" },
    {
      id: "actions",
      header: "Actions",
      width: 180,
      sticky: "end",
      render: (_entry, index) => (
        <DataGridRowActions
          disabled={locked}
          onAddBelow={() => addRecipient(index)}
          onRemove={() => removeEntry(index)}
          onMoveUp={index > 0 ? () => moveEntry(index, index - 1) : undefined}
          onMoveDown={index < entries.length - 1 ? () => moveEntry(index, index + 1) : undefined}
          addLabel="Add recipient below"
          removeLabel="Remove recipient"
          moveUpLabel="Move recipient up"
          moveDownLabel="Move recipient down"
        />
      )
    }
  ];
}

function getEntryAddresses(entry: Record<string, unknown>, key: EntryAddressColumn["key"]): MailboxAddress[] {
  if (key === "to") {
    const explicit = addressesFromValue(entry.to);
    return explicit.length ? explicit : fallbackRecipientAddress(entry);
  }
  if (key === "from") return addressesFromValue(entry.from).slice(0, 1);
  if (key === "reply_to") return addressesFromValue(entry.reply_to).slice(0, 1);
  return addressesFromValue(entry[key]);
}

function fallbackRecipientAddress(entry: Record<string, unknown>): MailboxAddress[] {
  const direct = addressesFromValue(entry.recipient)[0] ?? addressesFromValue(entry)[0];
  return direct?.email ? [direct] : [];
}

function uniqueEntryId(entries: Record<string, unknown>[], preferred: string): string {
  const existing = new Set(entries.map((entry) => String(entry.id || "")).filter(Boolean));
  if (!existing.has(preferred)) return preferred;
  let counter = entries.length + 1;
  let candidate = `recipient-${counter}`;
  while (existing.has(candidate)) {
    counter += 1;
    candidate = `recipient-${counter}`;
  }
  return candidate;
}
