"use client";

// Overlay wrapper for the nav-driven section panels of the /trade-in/v2
// "МЕРА Оценка" design. Faithful port of the design overlay container
// (МЕРА Оценка.dc.html lines 443-453 + 615-616): a glass/blur absolute layer
// with HUD corner brackets, a header (section number + title + "← К ОЦЕНКЕ"
// button) and a scrollable body that swaps the active view.

import { useEffect, useRef } from "react";

import { tokens } from "./tokens";
import { overlayNums, overlayTitles } from "./fixtures";
import HistoryView from "./HistoryView";
import SourcesView from "./SourcesView";
import AnalyticsView from "./AnalyticsView";
import { CacheView } from "./CacheView";
import type { CacheData, HistoryData, SourcesData } from "./mappers";
import type { Analytics } from "./types";
import type { AggregatedEstimate } from "@/types/trade-in";

interface SectionOverlayProps {
  active: number;
  onClose: () => void;
  onNavigate: (i: number) => void;
  // Mapped overlay data, fed by page.tsx (mapHistory / mapSources / mapAnalytics
  // / mapCache). Optional so unwired/storybook usage falls back to each view's
  // fixture default.
  history?: HistoryData;
  sources?: SourcesData;
  analytics?: Analytics;
  cache?: CacheData;
  // Raw current estimate — threaded straight to SourcesView's SourcesMap
  // (real per-lot lat/lon; sources/SourcesData above is pre-mapped display
  // strings with no geometry). Optional/null: no estimate yet -> map degrades
  // to its own honest-empty (renders nothing, tables still show).
  estimate?: AggregatedEstimate | null;
  // #2420 — «ПРЕДЫДУЩИЕ ОЦЕНКИ» row click: navigate to the full report for
  // that historical estimate. Optional (threaded straight to CacheView's own
  // optional onSelectRow — unwired usage leaves rows inert).
  onSelectEstimate?: (id: string) => void;
}

// Panel geometry (relative to the artboard). Kept as a constant so the click
// backdrop can align its top edge to the panel — the backdrop starts BELOW the
// TopNav so the top tabs stay clickable while an overlay is open.
const PANEL_TOP = 80;

export default function SectionOverlay({
  active,
  onClose,
  onNavigate,
  history,
  sources,
  analytics,
  cache,
  estimate = null,
  onSelectEstimate,
}: SectionOverlayProps) {
  // Non-modal dialog plumbing. `dialogRef` is the dialog root, `lastFocused`
  // keeps the element that had focus before the overlay opened so we can restore
  // it on close, and `onCloseRef` holds the latest onClose so the mount-only
  // effect (deps []) never re-runs / re-traps focus on parent re-renders even
  // though page.tsx passes a fresh arrow each render.
  const dialogRef = useRef<HTMLDivElement>(null);
  const bodyRef = useRef<HTMLDivElement>(null);
  const lastFocused = useRef<Element | null>(null);
  const onCloseRef = useRef(onClose);
  onCloseRef.current = onClose;

  // M7 — the overlay body is ONE scroller shared by every section view; switching
  // sections (nav within the overlay) used to inherit the previous section's
  // scroll offset, dropping the user into the middle of the new view. Reset to the
  // top whenever the active section changes.
  useEffect(() => {
    if (bodyRef.current) bodyRef.current.scrollTop = 0;
  }, [active]);

  useEffect(() => {
    const dialog = dialogRef.current;
    // Remember the trigger, then move focus into the dialog.
    lastFocused.current = document.activeElement;
    dialog?.focus();

    // This overlay is an HONEST NON-MODAL fullscreen view (no aria-modal): the
    // live top nav is a sibling that is deliberately NOT inerted, so a keyboard
    // user can switch sections from within the overlay. The Tab cycle therefore
    // spans [live nav tabs … + overlay content] in DOM order — we query the whole
    // artboard (the dialog's parent) and drop anything inside an inert subtree
    // (the dashboard body under the overlay). This keeps focus out of the hidden
    // <main>/<footer> while letting it flow between the nav and the overlay.
    const FOCUSABLE_SEL =
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';

    function getFocusable(): HTMLElement[] {
      const root = dialog?.parentElement;
      if (!root) return [];
      const nodes = root.querySelectorAll<HTMLElement>(FOCUSABLE_SEL);
      return Array.from(nodes).filter(
        (el) => !el.hasAttribute("disabled") && !el.closest("[inert]"),
      );
    }

    function onKeyDown(e: KeyboardEvent) {
      if (e.key === "Escape") {
        e.preventDefault();
        onCloseRef.current();
        return;
      }
      if (e.key !== "Tab" || !dialog) return;

      const focusable = getFocusable();
      if (focusable.length === 0) {
        // Nothing tabbable at all — keep focus pinned on the dialog itself.
        e.preventDefault();
        dialog.focus();
        return;
      }

      const root = dialog.parentElement;
      const first = focusable[0]; // first live nav tab
      const last = focusable[focusable.length - 1]; // last overlay control
      const activeEl = document.activeElement;
      const inRoot = root ? root.contains(activeEl) : false;

      // Only wrap at the two extremes; every middle step (incl. nav ↔ overlay)
      // uses the browser's native order, which already skips the inert body.
      if (e.shiftKey) {
        if (activeEl === first || !inRoot) {
          e.preventDefault();
          last.focus();
        }
      } else if (activeEl === last || !inRoot) {
        e.preventDefault();
        first.focus();
      }
    }

    document.addEventListener("keydown", onKeyDown);
    return () => {
      document.removeEventListener("keydown", onKeyDown);
      // Return focus to whatever opened the overlay.
      (lastFocused.current as HTMLElement | null)?.focus?.();
    };
    // Mount-only: refs (dialogRef/onCloseRef) are stable, so no extra deps.
  }, []);

  return (
    <>
      {/* Click-outside backdrop. A transparent layer covering the artboard BELOW
          the TopNav (top: PANEL_TOP) — clicking the margin area around the panel
          closes the overlay (in addition to Esc). It is a SIBLING of the dialog
          (not an ancestor) and sits one z-index below it, so clicks inside the
          panel / on its buttons never reach this handler (they don't bubble to a
          sibling) and therefore never close the overlay. Starting below the nav
          keeps the top tabs clickable. aria-hidden + no tabIndex → invisible to
          AT and keyboard; Esc remains the keyboard close path. */}
      <div
        aria-hidden="true"
        onClick={onClose}
        style={{
          position: "absolute",
          left: 0,
          right: 0,
          top: PANEL_TOP,
          bottom: 0,
          zIndex: 29,
        }}
      />

      <div
        ref={dialogRef}
        role="dialog"
        // No aria-modal: the top nav stays live/reachable behind this overlay
        // (only <main>/<footer> are inerted), so claiming full modality would be
        // dishonest to SR users (#2264 C1). role=dialog + label + focus mgmt stay.
        aria-labelledby="v2-overlay-title"
        tabIndex={-1}
        style={{
          position: "absolute",
          left: 28,
          right: 28,
          top: PANEL_TOP,
          bottom: 30,
          zIndex: 30,
          display: "flex",
          flexDirection: "column",
          background:
            "linear-gradient(180deg,rgba(244,248,252,.985),rgba(235,242,250,.985))",
          backdropFilter: "blur(12px)",
          border: `1px solid ${tokens.line3}`,
          borderRadius: 8,
          boxShadow: "0 22px 60px rgba(40,80,130,.18)",
          overflow: "hidden",
          fontFamily: tokens.font.sans,
        }}
      >
        <style>{`
          .tiv2-so-back {
            transition: all .15s;
            background: ${tokens.accentDeep};
            box-shadow: 0 3px 10px rgba(46,139,255,.28);
          }
          .tiv2-so-back:hover {
            box-shadow: 0 6px 16px rgba(46,139,255,.45);
            transform: translateY(-1px);
          }
          .tiv2-so-back:active {
            transform: translateY(0);
            box-shadow: 0 2px 6px rgba(46,139,255,.3);
          }
        `}</style>

        {/* HUD corner brackets */}
        <div
          style={{
            position: "absolute",
            left: 12,
            top: 12,
            width: 15,
            height: 15,
            borderLeft: `1.5px solid ${tokens.accent}`,
            borderTop: `1.5px solid ${tokens.accent}`,
            pointerEvents: "none",
          }}
        />
        <div
          style={{
            position: "absolute",
            right: 12,
            bottom: 12,
            width: 15,
            height: 15,
            borderRight: `1.5px solid ${tokens.accent}`,
            borderBottom: `1.5px solid ${tokens.accent}`,
            pointerEvents: "none",
          }}
        />

        {/* overlay header */}
        <div
          style={{
            flex: "0 0 auto",
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
            padding: "16px 24px",
            borderBottom: "1px solid #cdd9e6",
          }}
        >
          <div style={{ display: "flex", alignItems: "baseline", gap: 11 }}>
            <span
              style={{
                fontFamily: tokens.font.mono,
                fontSize: 15,
                // accentDeep (not accent): the section number is 15px mono text,
                // and accent #2e8bff on the near-white overlay header is only
                // ~2.9:1; accentDeep #0d6fd6 clears AA (#2264 C4).
                color: tokens.accentDeep,
              }}
            >
              {overlayNums[active]}
            </span>
            {/* Section heading — real <h2> (page h1 is the sr-only «Мера …»).
                Preflight is not loaded here, so the h2 UA defaults are reset
                inline (margin/size/weight) to keep the visuals unchanged. */}
            <h2
              id="v2-overlay-title"
              style={{
                margin: 0,
                fontSize: 14,
                fontWeight: 600,
                letterSpacing: 2.5,
                color: tokens.ink2,
              }}
            >
              {overlayTitles[active]}
            </h2>
          </div>
          <button
            type="button"
            onClick={onClose}
            className="tiv2-so-back"
            aria-label="Вернуться к оценке"
            style={{
              display: "flex",
              alignItems: "center",
              gap: 8,
              cursor: "pointer",
              border: `1px solid ${tokens.accentDeep}`,
              borderRadius: 6,
              padding: "8px 15px",
              // background + shadow live in .tiv2-so-back so :hover can override
              // them (an inline background would beat the hover rule on
              // specificity). Solid accentDeep keeps white text ≥4.5:1 (AA).
              fontFamily: "inherit",
            }}
          >
            <span
              style={{ fontSize: 15, color: tokens.onAccent, lineHeight: 1 }}
            >
              ←
            </span>
            <span
              style={{
                fontSize: 11,
                fontWeight: 600,
                letterSpacing: 1.5,
                color: tokens.onAccent,
              }}
            >
              К ОЦЕНКЕ
            </span>
          </button>
        </div>

        {/* overlay body */}
        <div
          ref={bodyRef}
          style={{
            flex: 1,
            minHeight: 0,
            overflowY: "auto",
            padding: "22px 24px 26px",
          }}
        >
          {active === 1 && <HistoryView data={history} />}
          {active === 2 && <SourcesView data={sources} estimate={estimate} />}
          {active === 3 && (
            <AnalyticsView data={analytics} onNavigate={onNavigate} />
          )}
          {active === 4 && (
            <CacheView data={cache} onSelectRow={onSelectEstimate} />
          )}
        </div>
      </div>
    </>
  );
}
