/**
 * SessionMenu — top-bar dropdown that drives the SessionService.
 *
 * Holds the only place in the UI where sessions get created, renamed,
 * deleted, and switched. Export/Import ZIP menu items are slots —
 * T06/T07 wire them.
 *
 * Switching sessions writes the new id into the URL hash; the routing
 * layer is the source of truth (see `routing.ts`). That keeps deep
 * links + browser back/forward behaving naturally.
 */

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import type { CSSProperties } from "react";

import type { SessionId } from "@shared/ids";
import type { Session } from "@shared/session";
import { useActiveSession, useSessionListTick, useSessionService } from "@work/index";
import { clearAllSessionData } from "@engine/index";

import { navigateTo } from "./routing";

interface SessionMenuProps {
  readonly onExportZip?: () => void;
  readonly onImportZip?: () => void;
  readonly onOpenSamples?: () => void;
}

export function SessionMenu({ onExportZip, onImportZip, onOpenSamples }: SessionMenuProps) {
  const service = useSessionService();
  const tick = useSessionListTick();
  const active = useActiveSession();

  const [open, setOpen] = useState(false);
  const [newName, setNewName] = useState("");
  const [creating, setCreating] = useState(false);
  const [renaming, setRenaming] = useState(false);
  const [renameValue, setRenameValue] = useState("");
  const [pendingDelete, setPendingDelete] = useState(false);
  /** Per-row delete confirmation: id of the session armed for delete. */
  const [pendingRowDelete, setPendingRowDelete] = useState<SessionId | null>(null);
  const [pendingResetAll, setPendingResetAll] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const wrapperRef = useRef<HTMLDivElement | null>(null);

  const sessions = useMemo(() => {
    // sorted by lastOpenedAt desc, then by createdAt desc
    void tick;
    const list = [...service.list()];
    list.sort((a: Session, b: Session) => {
      const aKey = a.lastOpenedAt ?? a.createdAt;
      const bKey = b.lastOpenedAt ?? b.createdAt;
      return bKey.localeCompare(aKey);
    });
    return list;
  }, [service, tick]);

  // Click outside closes the menu.
  useEffect(() => {
    if (!open) return;
    const handler = (e: MouseEvent) => {
      if (!wrapperRef.current) return;
      if (!wrapperRef.current.contains(e.target as Node)) {
        setOpen(false);
        setCreating(false);
        setRenaming(false);
        setPendingDelete(false);
        setPendingRowDelete(null);
        setPendingResetAll(false);
      }
    };
    window.addEventListener("mousedown", handler);
    return () => window.removeEventListener("mousedown", handler);
  }, [open]);

  // Auto-clear pending row-delete after a few seconds so the user
  // doesn't accidentally double-click much later and lose data.
  useEffect(() => {
    if (!pendingRowDelete) return;
    const t = setTimeout(() => setPendingRowDelete(null), 3000);
    return () => clearTimeout(t);
  }, [pendingRowDelete]);

  useEffect(() => {
    if (!pendingResetAll) return;
    const t = setTimeout(() => setPendingResetAll(false), 5000);
    return () => clearTimeout(t);
  }, [pendingResetAll]);

  const switchTo = useCallback(
    (sessionId: import("@shared/ids").SessionId) => {
      navigateTo({ sessionId, mode: "review" });
      setOpen(false);
    },
    [],
  );

  const handleCreate = useCallback(() => {
    setError(null);
    try {
      const created = service.create(newName);
      setNewName("");
      setCreating(false);
      setOpen(false);
      navigateTo({ sessionId: created.id, mode: "review" });
    } catch (err) {
      setError(err instanceof Error ? err.message : String(err));
    }
  }, [newName, service]);

  const handleRename = useCallback(() => {
    if (!active) return;
    setError(null);
    try {
      service.rename(active.id, renameValue);
      setRenaming(false);
      setOpen(false);
    } catch (err) {
      setError(err instanceof Error ? err.message : String(err));
    }
  }, [active, renameValue, service]);

  const handleDelete = useCallback(() => {
    if (!active) return;
    if (!pendingDelete) {
      setPendingDelete(true);
      return;
    }
    service.delete(active.id);
    setPendingDelete(false);
    setOpen(false);
    navigateTo({ sessionId: null, mode: "review" });
  }, [active, pendingDelete, service]);

  const handleRowDelete = useCallback(
    (e: React.MouseEvent, id: SessionId) => {
      e.stopPropagation();
      if (pendingRowDelete !== id) {
        setPendingRowDelete(id);
        return;
      }
      const wasActive = active?.id === id;
      service.delete(id);
      setPendingRowDelete(null);
      if (wasActive) {
        setOpen(false);
        navigateTo({ sessionId: null, mode: "review" });
      }
    },
    [active, pendingRowDelete, service],
  );

  const handleResetAll = useCallback(() => {
    if (!pendingResetAll) {
      setPendingResetAll(true);
      return;
    }
    clearAllSessionData();
    setPendingResetAll(false);
    setOpen(false);
    // Force a full reload so every in-memory cache (sessions repo,
    // byte stores, engine snapshots) starts fresh from the cleared
    // localStorage.
    if (typeof window !== "undefined") {
      window.location.hash = "";
      window.location.reload();
    }
  }, [pendingResetAll]);

  return (
    <div ref={wrapperRef} style={{ position: "relative" }} data-testid="session-menu">
      <button
        type="button"
        aria-haspopup="menu"
        aria-expanded={open}
        data-testid="session-menu-toggle"
        onClick={() => setOpen((v) => !v)}
        style={{
          fontSize: 12,
          padding: "4px 10px",
          border: "1px solid #888",
          background: "white",
          cursor: "pointer",
          minWidth: 160,
          textAlign: "left",
        }}
      >
        {active ? active.name : "No session"}
        <span style={{ float: "right", color: "#888" }}>▾</span>
      </button>
      {open && (
        <div
          role="menu"
          data-testid="session-menu-panel"
          style={{
            position: "absolute",
            top: 28,
            left: 0,
            zIndex: 30,
            background: "white",
            border: "1px solid #888",
            borderRadius: 3,
            boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
            padding: 4,
            minWidth: 240,
            fontSize: 12,
          }}
        >
          {sessions.length > 0 && (
            <>
              <div style={{ padding: "4px 8px", color: "#666", fontSize: 11 }}>
                Switch to…
              </div>
              {sessions.map((s) => {
                const rowArmed = pendingRowDelete === s.id;
                return (
                  <div
                    key={s.id}
                    style={{
                      display: "flex",
                      alignItems: "center",
                      background: active?.id === s.id ? "#e8f0ff" : "transparent",
                    }}
                  >
                    <button
                      type="button"
                      role="menuitem"
                      data-testid={`session-switch-${s.id}`}
                      onClick={() => switchTo(s.id)}
                      style={{ ...menuItemStyle, flex: 1 }}
                    >
                      {s.name}
                      {active?.id === s.id ? " · open" : ""}
                    </button>
                    <button
                      type="button"
                      aria-label={`Delete session ${s.name}`}
                      data-testid={`session-row-delete-${s.id}`}
                      onClick={(e) => handleRowDelete(e, s.id)}
                      title={rowArmed ? "Click again to confirm" : "Delete session and drop all its data"}
                      style={{
                        background: rowArmed ? "#ffe5e5" : "transparent",
                        border: "none",
                        color: "#7a0000",
                        cursor: "pointer",
                        padding: "4px 8px",
                        fontSize: 14,
                        lineHeight: 1,
                      }}
                    >
                      {rowArmed ? "Confirm?" : "✕"}
                    </button>
                  </div>
                );
              })}
              <hr style={dividerStyle} />
            </>
          )}

          {!creating && (
            <button
              type="button"
              role="menuitem"
              data-testid="session-menu-new"
              onClick={() => {
                setError(null);
                setCreating(true);
                setNewName("");
              }}
              style={menuItemStyle}
            >
              New session…
            </button>
          )}
          {creating && (
            <div style={{ padding: 4, display: "flex", gap: 4 }}>
              <input
                autoFocus
                type="text"
                value={newName}
                onChange={(e) => setNewName(e.target.value)}
                placeholder="Session name"
                data-testid="session-new-input"
                style={{ flex: 1, fontSize: 12, padding: 4 }}
                onKeyDown={(e) => {
                  if (e.key === "Enter") handleCreate();
                  if (e.key === "Escape") setCreating(false);
                }}
              />
              <button
                type="button"
                onClick={handleCreate}
                data-testid="session-new-confirm"
                style={smallButtonStyle}
              >
                Create
              </button>
            </div>
          )}

          {active && (
            <>
              <hr style={dividerStyle} />
              {!renaming && (
                <button
                  type="button"
                  role="menuitem"
                  data-testid="session-menu-rename"
                  onClick={() => {
                    setError(null);
                    setRenaming(true);
                    setRenameValue(active.name);
                  }}
                  style={menuItemStyle}
                >
                  Rename…
                </button>
              )}
              {renaming && (
                <div style={{ padding: 4, display: "flex", gap: 4 }}>
                  <input
                    autoFocus
                    type="text"
                    value={renameValue}
                    onChange={(e) => setRenameValue(e.target.value)}
                    data-testid="session-rename-input"
                    style={{ flex: 1, fontSize: 12, padding: 4 }}
                    onKeyDown={(e) => {
                      if (e.key === "Enter") handleRename();
                      if (e.key === "Escape") setRenaming(false);
                    }}
                  />
                  <button
                    type="button"
                    onClick={handleRename}
                    data-testid="session-rename-confirm"
                    style={smallButtonStyle}
                  >
                    Save
                  </button>
                </div>
              )}
              <button
                type="button"
                role="menuitem"
                data-testid="session-menu-delete"
                onClick={handleDelete}
                style={{ ...menuItemStyle, color: "#7a0000" }}
              >
                {pendingDelete ? "Confirm delete?" : "Delete…"}
              </button>
            </>
          )}

          {(onExportZip || onImportZip || onOpenSamples) && (
            <hr style={dividerStyle} />
          )}
          {onExportZip && active && (
            <button
              type="button"
              role="menuitem"
              data-testid="session-menu-export"
              onClick={() => {
                setOpen(false);
                onExportZip();
              }}
              style={menuItemStyle}
            >
              Export ZIP
            </button>
          )}
          {onImportZip && (
            <button
              type="button"
              role="menuitem"
              data-testid="session-menu-import"
              onClick={() => {
                setOpen(false);
                onImportZip();
              }}
              style={menuItemStyle}
            >
              Import ZIP
            </button>
          )}
          {onOpenSamples && (
            <button
              type="button"
              role="menuitem"
              data-testid="session-menu-samples"
              onClick={() => {
                setOpen(false);
                onOpenSamples();
              }}
              style={menuItemStyle}
            >
              Sample sessions ▸
            </button>
          )}

          <hr style={dividerStyle} />
          <button
            type="button"
            role="menuitem"
            data-testid="session-menu-reset-all"
            onClick={handleResetAll}
            title="Wipe every session, every uploaded PDF, every annotation — and reload."
            style={{ ...menuItemStyle, color: "#7a0000" }}
          >
            {pendingResetAll
              ? "Confirm — wipe everything?"
              : "Reset all data…"}
          </button>

          {error && (
            <div
              data-testid="session-menu-error"
              style={{
                padding: 6,
                background: "#fff4f4",
                color: "#7a0000",
                fontSize: 11,
                marginTop: 4,
              }}
            >
              {error}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

const menuItemStyle: CSSProperties = {
  display: "block",
  width: "100%",
  textAlign: "left",
  background: "transparent",
  border: "none",
  padding: "4px 8px",
  cursor: "pointer",
  fontSize: 12,
};

const smallButtonStyle: CSSProperties = {
  fontSize: 12,
  padding: "2px 8px",
  border: "1px solid #888",
  background: "white",
  cursor: "pointer",
};

const dividerStyle: CSSProperties = {
  border: "none",
  borderTop: "1px solid #eee",
  margin: "4px 0",
};
