import { useEffect, useMemo, useRef, useState } from "react";
import { Link } from "react-router-dom";
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 ToggleSwitch from "../../components/ToggleSwitch";
import { autosaveCampaignVersion } from "../../api/campaigns";
import { useCampaignWorkspaceData } from "./hooks/useCampaignWorkspaceData";
import { asArray, asRecord, formatDateTime, getCampaignJson, isAuditLockedVersion, isRecord, stringifyPreview, versionLockReason } from "./utils/campaignView";
import { ensureCampaignDraft, getBool, getText, updateNested } from "./utils/draftEditor";
import { useRegisterCampaignUnsavedChanges } from "./context/UnsavedChangesContext";

const behaviorOptions = ["block", "ask", "drop", "continue", "warn"];

type AttachmentRule = Record<string, unknown>;

export default function AttachmentsDataPage({ settings, campaignId }: { settings: ApiSettings; campaignId: string }) {
  const { data, loading, error, reload, setError } = useCampaignWorkspaceData(settings, campaignId);
  const [draft, setDraft] = useState<Record<string, unknown> | null>(null);
  const [dirty, setDirty] = useState(false);
  const [saveState, setSaveState] = useState("Loaded");
  const [localError, setLocalError] = useState("");
  const loadedVersionId = useRef<string | null>(null);

  const version = data.currentVersion;
  const locked = isAuditLockedVersion(version);
  const attachments = asRecord(draft?.attachments);
  const globalRules = useMemo(() => normalizeAttachmentRules(attachments.global), [attachments.global]);
  const entries = asRecord(draft?.entries);
  const inlineEntries = asArray(entries.inline).map(asRecord);
  const individualRules = inlineEntries.flatMap((entry, index) => asArray(entry.attachments).map((rule) => ({ entry: String(entry.id || index + 1), ...asRecord(rule) })));

  useEffect(() => {
    if (!version) return;
    if (loadedVersionId.current === version.id) return;
    loadedVersionId.current = version.id;
    setDraft(ensureCampaignDraft(version));
    setDirty(false);
    setSaveState(version.autosaved_at ? `Loaded saved draft ${formatDateTime(version.autosaved_at)}` : "Loaded");
  }, [version]);


  function patch(path: string[], value: unknown) {
    if (locked) return;
    setDraft((current) => updateNested(current ?? {}, path, value));
    setDirty(true);
    setLocalError("");
  }

  function patchGlobalAttachment(index: number, patchValue: Partial<AttachmentRule>) {
    const nextRules = globalRules.map((rule, currentIndex) => currentIndex === index ? { ...rule, ...patchValue } : rule);
    patch(["attachments", "global"], nextRules);
  }

  function addGlobalAttachment() {
    const nextRules: AttachmentRule[] = [
      ...globalRules,
      {
        id: `global-${Date.now()}`,
        label: "",
        base_dir: "",
        file_filter: "",
        required: true,
        include_subdirs: false,
        allow_multiple: false,
        missing_behavior: getText(attachments, "missing_behavior", "ask"),
        ambiguous_behavior: getText(attachments, "ambiguous_behavior", "ask")
      }
    ];
    patch(["attachments", "global"], nextRules);
  }

  function removeGlobalAttachment(index: number) {
    patch(["attachments", "global"], globalRules.filter((_, currentIndex) => currentIndex !== index));
  }

  async function saveDraft(mode: "auto" | "manual" = "manual"): Promise<boolean> {
    if (!draft || !version || locked) return false;
    setSaveState("Saving…");
    setError("");
    setLocalError("");
    try {
      const saved = await autosaveCampaignVersion(settings, campaignId, version.id, {
        campaign_json: draft,
        current_flow: "manual",
        current_step: "files",
        workflow_state: "editing",
        is_complete: false
      });
      setDraft(getCampaignJson(saved));
      setDirty(false);
      setSaveState(`Saved ${formatDateTime(saved.autosaved_at ?? saved.updated_at)}`);
      await reload();
      return true;
    } catch (err) {
      const text = err instanceof Error ? err.message : String(err);
      setLocalError(text);
      setSaveState("Save failed");
      return false;
    }
  }

  useRegisterCampaignUnsavedChanges(dirty && !locked ? {
    title: "Unsaved attachment settings",
    message: "Attachment settings have unsaved changes. Save them before leaving, or discard them and continue.",
    onSave: () => saveDraft("manual"),
    onDiscard: () => setDirty(false)
  } : null);

  return (
    <div className="content-pad workspace-data-page">
      <div className="page-heading split workspace-heading">
        <div>
          <PageTitle loading={loading}>Attachments</PageTitle>
          <p className="mono-small">Version {version ? `#${version.version_number}` : "—"} · {saveState}</p>
        </div>
        <div className="button-row compact-actions">
          <Button disabled>Manage files</Button>
          <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>}

      {draft && (
        <>
          <div className="dashboard-grid">
            <Card title="Attachment area">
              <dl className="detail-list">
                <div><dt>Attachment base path</dt><dd>{String(attachments.base_path || ".")}</dd></div>
                <div><dt>Global files</dt><dd>{globalRules.length}</dd></div>
                <div><dt>Per-recipient patterns</dt><dd>{individualRules.length}</dd></div>
                <div><dt>Upload support</dt><dd>Planned</dd></div>
              </dl>
            </Card>
            <Card title="Campaign file storage">
              <p className="muted">This section will become the Garage/S3-backed file picker for tenant, group and campaign attachment areas.</p>
              <div className="placeholder-stack">
                <span>Upload campaign files</span>
                <span>Pick files for global attachment rules</span>
                <span>Resolve missing or ambiguous individual matches</span>
              </div>
            </Card>
          </div>

          <Card title="Global attachment files" actions={<Button onClick={addGlobalAttachment} disabled={locked}>Add file</Button>}>
            <div className="attachment-base-stack">
              <div className="attachment-base-grid">
                <FormField label="Attachment base path"><input value={getText(attachments, "base_path", ".")} disabled={locked} onChange={(event) => patch(["attachments", "base_path"], event.target.value)} /></FormField>
                <div className="attachment-base-toggle"><ToggleSwitch label="Allow individual attachments" checked={getBool(attachments, "allow_individual")} disabled={locked} onChange={(checked) => patch(["attachments", "allow_individual"], checked)} /></div>
              </div>
              <div className="form-grid compact responsive-form-grid">
                <FormField label="Default missing behavior"><select value={getText(attachments, "missing_behavior", "ask")} disabled={locked} onChange={(event) => patch(["attachments", "missing_behavior"], event.target.value)}>{behaviorOptions.map((option) => <option key={option}>{option}</option>)}</select></FormField>
                <FormField label="Default ambiguous behavior"><select value={getText(attachments, "ambiguous_behavior", "ask")} disabled={locked} onChange={(event) => patch(["attachments", "ambiguous_behavior"], event.target.value)}>{behaviorOptions.map((option) => <option key={option}>{option}</option>)}</select></FormField>
              </div>
            </div>

            {globalRules.length === 0 ? (
              <p className="muted small-note">No global files selected. Add files here only if every message should include them.</p>
            ) : (
              <div className="app-table-wrap compact-table-wrap">
                <table className="app-table direct-attachment-table">
                  <thead>
                    <tr>
                      <th>Label</th>
                      <th>Base dir</th>
                      <th>Selected file / pattern</th>
                      <th>Required</th>
                      <th>Include subdirs</th>
                      <th></th>
                    </tr>
                  </thead>
                  <tbody>
                    {globalRules.map((rule, index) => (
                      <tr key={String(rule.id ?? index)}>
                        <td><input value={getText(rule, "label")} disabled={locked} placeholder="Attachment label" onChange={(event) => patchGlobalAttachment(index, { label: event.target.value })} /></td>
                        <td><input value={getText(rule, "base_dir")} disabled={locked} placeholder="optional/folder" onChange={(event) => patchGlobalAttachment(index, { base_dir: event.target.value })} /></td>
                        <td><input value={getText(rule, "file_filter")} disabled={locked} placeholder="file.pdf or {{field}}.pdf" onChange={(event) => patchGlobalAttachment(index, { file_filter: event.target.value })} /></td>
                        <td><ToggleSwitch label="Required" checked={getBool(rule, "required", true)} disabled={locked} onChange={(checked) => patchGlobalAttachment(index, { required: checked })} /></td>
                        <td><ToggleSwitch label="Subdirs" checked={getBool(rule, "include_subdirs")} disabled={locked} onChange={(checked) => patchGlobalAttachment(index, { include_subdirs: checked })} /></td>
                        <td className="table-action-cell"><Button variant="danger" onClick={() => removeGlobalAttachment(index)} disabled={locked}>Remove</Button></td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </Card>

          <Card title="Per-recipient file patterns" actions={<Link to="../recipients"><Button>Open recipients</Button></Link>}>
            <p className="muted small-note">Individual file patterns can be edited on each recipient row. They are summarized here because file matching and upload review also belong to the Attachments workflow.</p>
            <div className="app-table-wrap data-table-wrap">
              <table className="app-table files-table">
                <thead>
                  <tr>
                    <th>Recipient / entry</th>
                    <th>Label</th>
                    <th>Base dir</th>
                    <th>Filter</th>
                    <th>Options</th>
                  </tr>
                </thead>
                <tbody>
                  {individualRules.length === 0 && (
                    <tr><td colSpan={5} className="muted">No per-recipient file patterns are configured yet.</td></tr>
                  )}
                  {individualRules.map((rule, index) => <RuleRow key={`individual-${index}`} scope={`Entry ${rule.entry}`} rule={rule} />)}
                </tbody>
              </table>
            </div>
          </Card>

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

function RuleRow({ scope, rule }: { scope: string; rule: Record<string, unknown> }) {
  return (
    <tr>
      <td>{scope}</td>
      <td>{String(rule.label || rule.id || "—")}</td>
      <td><code>{String(rule.base_dir || "—")}</code></td>
      <td><code>{String(rule.file_filter || "—")}</code></td>
      <td><code>{stringifyPreview({ required: rule.required, allow_multiple: rule.allow_multiple, zip: rule.zip }, 120)}</code></td>
    </tr>
  );
}

function normalizeAttachmentRules(value: unknown): AttachmentRule[] {
  if (!Array.isArray(value)) return [];
  return value.filter(isRecord).map((rule) => ({
    id: getText(rule, "id", `global-${Math.random().toString(36).slice(2)}`),
    label: getText(rule, "label"),
    base_dir: getText(rule, "base_dir", ""),
    file_filter: getText(rule, "file_filter"),
    include_subdirs: getBool(rule, "include_subdirs"),
    required: getBool(rule, "required", true),
    allow_multiple: getBool(rule, "allow_multiple"),
    missing_behavior: getText(rule, "missing_behavior", "ask"),
    ambiguous_behavior: getText(rule, "ambiguous_behavior", "ask"),
    ...(isRecord(rule.zip) ? { zip: rule.zip } : {})
  }));
}
