"use client";

import { Check, ChevronDown, Database, Pencil, Plus, Save, ShieldAlert, TrendingUp, Trash2, X } from "lucide-react";
import { useState } from "react";

import type { Memory, MemoryPreferenceDefinition, MemoryValue, PreferenceSignal } from "@/lib/types";

const MEMORY_LABELS: Record<string, string> = {
  minimum_arrival_buffer_minutes: "Arrival buffer",
  max_hotel_nightly_cad: "Hotel ceiling",
  seat_preference: "Seat preference",
  home_airport: "Home airport",
  trip_budget_cad: "Trip budget",
  favorite_teams: "Favorite teams",
  accessibility_needs: "Accessibility",
  dietary_needs: "Dietary needs",
  preferred_currency: "Currency",
  preferred_host_cities: "Preferred host cities",
  preferred_countries: "Preferred countries",
  budget_style: "Budget style",
  max_hotel_to_stadium_minutes: "Hotel-to-stadium limit",
  max_walking_minutes: "Walking limit",
  max_layover_minutes: "Layover limit",
  preferred_package_style: "Package style",
  max_vacation_rental_nightly_cad: "Vacation-rental ceiling",
  max_vacation_rental_to_stadium_minutes: "Rental-to-stadium limit",
  minimum_rental_bedrooms: "Minimum rental bedrooms",
  preferred_activity_categories: "Activity interests",
  max_activity_price_cad: "Activity price ceiling",
  preferred_vehicle_class: "Preferred vehicle class",
  preferred_cruise_style: "Cruise style",
  preferred_traveler_profile: "Traveler profile",
};

function titleCase(value: string): string {
  return value
    .replaceAll("_", " ")
    .replace(/\b\w/g, (character) => character.toUpperCase());
}

function displayValue(memory: Memory): string {
  if (memory.value.label) return memory.value.label;
  if (Array.isArray(memory.value.value)) return memory.value.value.join(", ");
  return `${memory.value.value}${memory.value.unit ? ` ${memory.value.unit}` : ""}`;
}

function correctedLabel(key: string, value: MemoryValue["value"]): string | null {
  if (key === "minimum_arrival_buffer_minutes" && typeof value === "number") {
    return `${value} minutes before kickoff`;
  }
  if (key === "max_hotel_nightly_cad" && typeof value === "number") {
    return `Hotel ceiling C$${value}/night`;
  }
  if (key === "seat_preference" && typeof value === "string") {
    return `${value.charAt(0).toUpperCase()}${value.slice(1)} seat`;
  }
  if (key === "max_vacation_rental_nightly_cad" && typeof value === "number") {
    return `Rental ceiling C$${value}/night`;
  }
  if (key === "max_vacation_rental_to_stadium_minutes" && typeof value === "number") {
    return `${value} minutes to stadium`;
  }
  if (key === "minimum_rental_bedrooms" && typeof value === "number") {
    return `${value} bedroom${value === 1 ? "" : "s"} minimum`;
  }
  if (key === "max_activity_price_cad" && typeof value === "number") {
    return `Activity ceiling C$${value}`;
  }
  if (key === "preferred_activity_categories" && Array.isArray(value)) {
    return value.map((item) => titleCase(String(item))).join(", ");
  }
  if (
    ["preferred_vehicle_class", "preferred_cruise_style", "preferred_traveler_profile"].includes(key)
    && typeof value === "string"
  ) {
    return titleCase(value);
  }
  return null;
}

function sourceLabel(source: string): string {
  const labels: Record<string, string> = {
    explicit_user: "Explicit user statement",
    user_action: "Explicit saved choice",
    behavior_inferred: "Repeated verified trips",
    demo_seed: "Demo profile seed",
    imported: "Imported profile",
  };
  return labels[source] || titleCase(source);
}

function scopeLabel(scope: string): string {
  if (scope === "fan_memory") return "Fan profile";
  if (scope === "trip_memory") return "This trip only";
  return titleCase(scope);
}

function shortDate(value: string): string {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "Unknown";
  return new Intl.DateTimeFormat("en-CA", {
    day: "numeric",
    month: "short",
    year: "numeric",
    timeZone: "UTC",
  }).format(date);
}

export function MemoryPanel({
  memories,
  signals,
  enabled,
  busy,
  onToggle,
  onDelete,
  onDismissSignal,
  onUpdate,
  catalog,
  onCreate,
}: {
  memories: Memory[];
  signals: PreferenceSignal[];
  enabled: boolean;
  busy: boolean;
  onToggle: (enabled: boolean) => Promise<void>;
  onDelete: (memoryId: string) => Promise<void>;
  onDismissSignal: (evidenceId: string) => Promise<void>;
  onUpdate: (memory: Memory, value: MemoryValue, excerpt: string) => Promise<boolean>;
  catalog: MemoryPreferenceDefinition[];
  onCreate: (key: string, value: MemoryValue["value"]) => Promise<boolean>;
}) {
  const [editing, setEditing] = useState<string | null>(null);
  const [draft, setDraft] = useState("");
  const [adding, setAdding] = useState(false);
  const [newKey, setNewKey] = useState("");
  const [newDraft, setNewDraft] = useState("");
  const [newSelections, setNewSelections] = useState<string[]>([]);
  const selectedDefinition = catalog.find((item) => item.key === newKey) || catalog[0];

  function beginEdit(memory: Memory) {
    setEditing(memory.id);
    setDraft(String(memory.value.value));
  }

  async function save(memory: Memory) {
    let value: MemoryValue["value"];
    if (typeof memory.value.value === "number") {
      const parsed = Number(draft);
      if (!Number.isFinite(parsed)) return;
      value = parsed;
    } else if (Array.isArray(memory.value.value)) {
      value = draft.split(",").map((item) => item.trim()).filter(Boolean);
      if (!value.length) return;
    } else {
      value = draft.trim();
      if (!value) return;
    }
    const saved = await onUpdate(
      memory,
      { ...memory.value, value, label: correctedLabel(memory.key, value) },
      `I corrected ${MEMORY_LABELS[memory.key] || memory.key} to ${draft.trim()}.`,
    );
    if (saved) setEditing(null);
  }

  function selectDefinition(key: string) {
    const definition = catalog.find((item) => item.key === key);
    setNewKey(key);
    setNewSelections([]);
    setNewDraft(definition?.value_kind === "select" ? definition.options[0] || "" : "");
  }

  function beginAdd() {
    const definition = catalog[0];
    if (!definition) return;
    setAdding(true);
    selectDefinition(definition.key);
  }

  async function saveNewPreference() {
    if (!selectedDefinition) return;
    let value: MemoryValue["value"];
    if (selectedDefinition.value_kind === "integer") {
      const parsed = Number(newDraft);
      if (!Number.isInteger(parsed)) return;
      if (selectedDefinition.minimum != null && parsed < selectedDefinition.minimum) return;
      if (selectedDefinition.maximum != null && parsed > selectedDefinition.maximum) return;
      value = parsed;
    } else if (selectedDefinition.value_kind === "list") {
      value = newDraft.split(",").map((item) => item.trim()).filter(Boolean);
      if (!value.length) return;
    } else if (selectedDefinition.value_kind === "multi_select") {
      value = newSelections;
      if (!value.length) return;
    } else {
      value = newDraft.trim();
      if (!value) return;
    }
    if (await onCreate(selectedDefinition.key, value)) {
      setAdding(false);
      setNewDraft("");
      setNewSelections([]);
    }
  }

  return (
    <section className="memory-panel" aria-labelledby="memory-title">
      <div className="section-heading">
        <div>
          <span className="eyebrow">Persistent profile</span>
          <h2 id="memory-title"><Database size={17} /> Fan memory</h2>
        </div>
        <label className="switch" title="Enable or disable persistent memory">
          <input
            id="persistent-fan-memory"
            name="persistent-fan-memory"
            aria-label="Persistent fan memory"
            type="checkbox"
            checked={enabled}
            disabled={busy}
            onChange={(event) => void onToggle(event.target.checked)}
          />
          <span aria-hidden="true" />
          <b>{enabled ? "On" : "Off"}</b>
        </label>
      </div>

      <div className="memory-toolbar">
        <button
          className="secondary-button memory-add-button"
          disabled={busy || !enabled || !catalog.length}
          onClick={beginAdd}
        >
          <Plus size={14} aria-hidden="true" /> Add preference
        </button>
      </div>

      {adding && selectedDefinition ? (
        <div className="memory-add-form" role="group" aria-label="Add profile preference">
          <label>
            <span>Preference</span>
            <select
              aria-label="Preference type"
              value={selectedDefinition.key}
              disabled={busy}
              onChange={(event) => selectDefinition(event.target.value)}
            >
              {catalog.map((definition) => (
                <option key={definition.key} value={definition.key}>{definition.label}</option>
              ))}
            </select>
          </label>
          <label>
            <span>Value</span>
            {selectedDefinition.value_kind === "select" ? (
              <select
                aria-label="Preference value"
                value={newDraft}
                disabled={busy}
                onChange={(event) => setNewDraft(event.target.value)}
              >
                {selectedDefinition.options.map((option) => (
                  <option key={option} value={option}>{titleCase(option)}</option>
                ))}
              </select>
            ) : selectedDefinition.value_kind === "multi_select" ? (
              <select
                aria-label="Preference values"
                multiple
                value={newSelections}
                disabled={busy}
                onChange={(event) => setNewSelections(
                  Array.from(event.target.selectedOptions, (option) => option.value),
                )}
              >
                {selectedDefinition.options.map((option) => (
                  <option key={option} value={option}>{titleCase(option)}</option>
                ))}
              </select>
            ) : (
              <input
                aria-label="Preference value"
                type={selectedDefinition.value_kind === "integer" ? "number" : "text"}
                min={selectedDefinition.minimum ?? undefined}
                max={selectedDefinition.maximum ?? undefined}
                placeholder={selectedDefinition.placeholder}
                value={newDraft}
                disabled={busy}
                onChange={(event) => setNewDraft(event.target.value)}
                onKeyDown={(event) => {
                  if (event.key === "Enter") void saveNewPreference();
                  if (event.key === "Escape") setAdding(false);
                }}
              />
            )}
          </label>
          <p>
            {selectedDefinition.description}
            {selectedDefinition.sensitivity === "private" ? " Kept private and excluded from public shares." : ""}
          </p>
          <div className="memory-add-actions">
            <button className="secondary-button" disabled={busy} onClick={() => void saveNewPreference()}>
              <Save size={14} aria-hidden="true" /> Save preference
            </button>
            <button className="icon-button" disabled={busy} onClick={() => setAdding(false)} aria-label="Cancel adding preference" title="Cancel">
              <X size={15} />
            </button>
          </div>
        </div>
      ) : null}

      <div className={`memory-list ${enabled ? "" : "is-disabled"}`}>
        {!memories.length && !signals.length ? (
          <p className="memory-empty-note">
            {busy ? "Loading confirmed preferences…" : "No confirmed preferences yet."}
          </p>
        ) : null}
        {memories.map((memory) => (
          <div className="memory-row" key={memory.id} data-memory-key={memory.key}>
            <span className="memory-status" title="Confirmed memory"><Check size={12} /></span>
            <div className="memory-body">
              <span>{MEMORY_LABELS[memory.key] || memory.key.replaceAll("_", " ")}</span>
              {editing === memory.id ? (
                <input
                  id={`memory-${memory.id}-value`}
                  name={`memory-${memory.key}`}
                  aria-label={`Edit ${MEMORY_LABELS[memory.key] || memory.key}`}
                  className="memory-input"
                  value={draft}
                  disabled={busy}
                  onChange={(event) => setDraft(event.target.value)}
                  onKeyDown={(event) => {
                    if (event.key === "Enter") void save(memory);
                    if (event.key === "Escape") setEditing(null);
                  }}
                  autoFocus
                />
              ) : (
                <>
                  <strong>{displayValue(memory)}</strong>
                  <details className="memory-disclosure">
                    <summary aria-label={`Inspect provenance for ${MEMORY_LABELS[memory.key] || memory.key} memory`}>
                      Inspect provenance <ChevronDown size={12} aria-hidden="true" />
                    </summary>
                    <div className="memory-provenance" data-memory-provenance>
                      <div><span>Source</span><b>{sourceLabel(memory.source_kind)}</b></div>
                      <div><span>Confidence</span><b>{Math.round(memory.confidence * 100)}%</b></div>
                      <div><span>Scope</span><b>{scopeLabel(memory.scope)}</b></div>
                      <div><span>Version</span><b>v{memory.version}</b></div>
                      <div><span>Updated</span><b>{shortDate(memory.updated_at)}</b></div>
                      <div>
                        <span>Expiry</span>
                        <b>{memory.expires_at ? shortDate(memory.expires_at) : "No automatic expiry"}</b>
                      </div>
                      <p>
                        <span>Grounded evidence</span>
                        <q>{memory.source_excerpt}</q>
                      </p>
                      {memory.sensitivity === "private" ? (
                        <small><ShieldAlert size={11} aria-hidden="true" /> Private — excluded from public shares</small>
                      ) : null}
                    </div>
                  </details>
                </>
              )}
            </div>
            <div className="icon-actions">
              {editing === memory.id ? (
                <>
                  <button className="icon-button" disabled={busy} onClick={() => void save(memory)} title="Save memory" aria-label="Save memory"><Save size={15} /></button>
                  <button className="icon-button" disabled={busy} onClick={() => setEditing(null)} title="Cancel edit" aria-label="Cancel edit"><X size={15} /></button>
                </>
              ) : (
                <>
                  <button className="icon-button" disabled={busy} onClick={() => beginEdit(memory)} title="Correct memory" aria-label="Correct memory"><Pencil size={14} /></button>
                  <button className="icon-button danger" disabled={busy} onClick={() => void onDelete(memory.id)} title="Delete memory" aria-label="Delete memory"><Trash2 size={14} /></button>
                </>
              )}
            </div>
          </div>
        ))}
        {signals.map((signal) => (
          <div className="memory-row memory-signal-row" key={signal.id} data-memory-signal={signal.key}>
            <span
              className={`memory-status is-${signal.status}`}
              title={signal.status === "confirmed" ? "Learned preference" : signal.status === "conflicted" ? "Held behind explicit memory" : "Learning signal"}
            >
              {signal.status === "conflicted" ? <ShieldAlert size={12} /> : <TrendingUp size={12} />}
            </span>
            <div className="memory-body">
              <span>{MEMORY_LABELS[signal.key] || signal.key.replaceAll("_", " ")} · learning evidence</span>
              <strong>{signal.value.label || String(signal.value.value)}</strong>
              <small>
                {signal.status === "confirmed"
                  ? `Learned from ${signal.distinct_trip_count} verified trips`
                  : signal.status === "conflicted"
                    ? "Not used because an explicit preference wins"
                    : `${signal.distinct_trip_count} of 2 verified trips · not used yet`}
              </small>
            </div>
            <div className="icon-actions">
              <button
                className="icon-button danger"
                disabled={busy}
                onClick={() => void onDismissSignal(signal.id)}
                title="Dismiss learning signal"
                aria-label="Dismiss learning signal"
              >
                <Trash2 size={14} />
              </button>
            </div>
          </div>
        ))}
      </div>
    </section>
  );
}
