import { useMemo } from "react";
import { Link } from "react-router-dom";
import type { ApiSettings } from "../../types";
import Button from "../../components/Button";
import Card from "../../components/Card";
import PageTitle from "../../components/PageTitle";
import LoadingFrame from "../../components/LoadingFrame";
import { useCampaignWorkspaceData } from "./hooks/useCampaignWorkspaceData";
import { useCampaignDraftEditor } from "./hooks/useCampaignDraftEditor";
import { asArray, asRecord, isAuditLockedVersion, isRecord, versionLockReason } from "./utils/campaignView";
import { getBool, getText } from "./utils/draftEditor";
import FieldValueInput from "./components/FieldValueInput";
import AttachmentRulesOverlay, { type AttachmentBasePath, type AttachmentRule } from "./components/AttachmentRulesOverlay";
import { addressesFromValue } from "../../utils/emailAddresses";

type FieldDefinition = {
  name: string;
  label: string;
  type: string;
  can_override: boolean;
};

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

  const version = data.currentVersion;
  const locked = isAuditLockedVersion(version);
  const { draft, displayDraft, dirty, saveState, localError, patch, saveDraft } = useCampaignDraftEditor({
    settings,
    campaignId,
    version,
    locked,
    reload,
    setError,
    currentStep: "recipient-data",
    unsavedTitle: "Unsaved recipient data changes",
    unsavedMessage: "Recipient field values or attachments have unsaved changes. Save them before leaving, or discard them and continue."
  });
  const entries = asRecord(displayDraft.entries);
  const inlineEntries = asArray(entries.inline).map(asRecord);
  const source = asRecord(entries.source);
  const fieldDefinitions = useMemo(() => getDraftFields(displayDraft), [displayDraft]);
  const attachmentSection = asRecord(displayDraft.attachments);
  const attachmentBasePaths = useMemo(() => normalizeAttachmentBasePaths(attachmentSection.base_paths, attachmentSection), [attachmentSection]);
  const individualAttachmentBasePaths = useMemo(() => {
    const enabled = attachmentBasePaths.filter((basePath) => basePath.allow_individual);
    return enabled.length > 0 ? enabled : attachmentBasePaths;
  }, [attachmentBasePaths]);


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

  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 updateEntryField(index: number, field: string, value: unknown) {
    updateEntry(index, (entry) => ({
      ...entry,
      fields: {
        ...asRecord(entry.fields),
        [field]: value
      }
    }));
  }

  function updateEntryAttachments(index: number, attachments: AttachmentRule[]) {
    updateEntry(index, (entry) => ({ ...entry, attachments }));
  }


  return (
    <div className="content-pad workspace-data-page">
      <div className="page-heading split workspace-heading">
        <div>
          <PageTitle loading={loading}>Recipient data</PageTitle>
          <p className="mono-small">Version {version ? `#${version.version_number}` : "—"} · {saveState}</p>
        </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 && <div className="alert danger">{error}</div>}
      {localError && <div className="alert danger">{localError}</div>}
      {locked && <div className="alert info">This version is read-only. {versionLockReason(version)}</div>}

      <LoadingFrame loading={loading || !draft} label="Loading campaign draft…">
        <>
          <Card title="Recipient field values and attachments">
            {inlineEntries.length === 0 && !source.type && <p className="muted">No recipient profiles are stored in the current version yet. Add recipients first, then maintain their data here.</p>}
            {inlineEntries.length === 0 && Boolean(source.type) && (
              <div className="alert info">This campaign references an external recipient source. A parsed data preview will be added when file/source preview support is implemented.</div>
            )}
            {inlineEntries.length > 0 && (
              <div className="app-table-wrap recipient-table-wrap recipient-data-table-wrap">
                <table className="app-table recipient-table recipient-data-table">
                  <thead>
                    <tr>
                      <th>#</th>
                      <th>Recipient</th>
                      <th>Attachments</th>
                      {fieldDefinitions.map((field) => <th key={field.name}>{field.label || field.name}</th>)}
                    </tr>
                  </thead>
                  <tbody>
                    {inlineEntries.slice(0, 100).map((entry, index) => {
                      const fields = asRecord(entry.fields);
                      const attachments = normalizeAttachmentRules(entry.attachments);
                      return (
                        <tr key={String(entry.id || index)}>
                          <td className="mono-small recipient-index-cell">{index + 1}</td>
                          <td className="recipient-data-identity-cell">
                            <Link className="recipient-data-identity" to="../recipients" title="Open recipient address profile">
                              <span className="recipient-data-address">{firstRecipientEmail(entry) || "No To address"}</span>
                              {extraRecipientCount(entry) > 0 && <span className="recipient-extra-bubble">+{extraRecipientCount(entry)}</span>}
                            </Link>
                          </td>
                          <td>
                            <AttachmentRulesOverlay
                              title={`Attachments for recipient ${index + 1}`}
                              rules={attachments}
                              disabled={locked}
                              basePaths={individualAttachmentBasePaths}
                              onChange={(rules) => updateEntryAttachments(index, rules)}
                            />
                          </td>
                          {fieldDefinitions.map((field) => (
                            <td key={field.name}>
                              <FieldValueInput
                                className="recipient-field-input"
                                fieldType={field.type}
                                value={fields[field.name]}
                                disabled={locked || field.can_override === false}
                                placeholder={field.can_override === false ? "Uses global value" : undefined}
                                onChange={(value) => updateEntryField(index, field.name, value)}
                              />
                            </td>
                          ))}
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            )}
          </Card>

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

function getDraftFields(draft: Record<string, unknown> | null): FieldDefinition[] {
  return asArray(draft?.fields)
    .map((field) => asRecord(field))
    .map((field) => ({
      name: getText(field, "name") || getText(field, "id"),
      label: getText(field, "label"),
      type: normalizeFieldType(getText(field, "type", "string")),
      can_override: getBool(field, "can_override", true)
    }))
    .filter((field) => Boolean(field.name));
}

function normalizeFieldType(value: string): string {
  return ["integer", "double", "date", "password"].includes(value) ? value : "string";
}

function firstRecipientEmail(entry: Record<string, unknown>): string {
  return (addressesFromValue(entry.to)[0] ?? addressesFromValue(entry.recipient)[0] ?? addressesFromValue(entry)[0])?.email ?? "";
}

function extraRecipientCount(entry: Record<string, unknown>): number {
  const count = addressesFromValue(entry.to).length;
  return Math.max(0, count - 1);
}

function normalizeAttachmentBasePaths(value: unknown, attachments: Record<string, unknown>): AttachmentBasePath[] {
  if (Array.isArray(value) && value.length > 0) {
    return value.filter(isRecord).map((basePath, index) => ({
      id: getText(basePath, "id", `base-path-${index + 1}`),
      name: getText(basePath, "name", `Base path ${index + 1}`),
      source: getText(basePath, "source"),
      path: getText(basePath, "path", index === 0 ? getText(attachments, "base_path", ".") : "."),
      allow_individual: getBool(basePath, "allow_individual")
    }));
  }

  return [{
    id: "base-path-campaign",
    name: "Campaign files",
    path: getText(attachments, "base_path", "."),
    allow_individual: getBool(attachments, "allow_individual", true)
  }];
}

function normalizeAttachmentRules(value: unknown): AttachmentRule[] {
  if (!Array.isArray(value)) return [];
  return value.filter(isRecord).map((rule) => ({ ...rule }));
}
