"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { useQueryClient } from "@tanstack/react-query";

import { ChatDock } from "@/components/site-finder/ChatDock";
import { GateVerdictBanner } from "@/components/site-finder/GateVerdictBanner";
import { HorizonSelector } from "@/components/site-finder/HorizonSelector";
import { Section1ParcelInfo } from "@/components/site-finder/analysis/Section1ParcelInfo";
import { Section2NetworksUtilities } from "@/components/site-finder/analysis/Section2NetworksUtilities";
import { Section3SettingsAndCompetitors } from "@/components/site-finder/analysis/Section3SettingsAndCompetitors";
import { Section4Estimate } from "@/components/site-finder/analysis/Section4Estimate";
import { Section5Atmosphere } from "@/components/site-finder/analysis/Section5Atmosphere";
import { Section6Forecast } from "@/components/site-finder/analysis/Section6Forecast";
import { Section7Concept } from "@/components/site-finder/analysis/Section7Concept";
import { SectionAlternatives } from "@/components/site-finder/analysis/SectionAlternatives";
import { adaptEgrn, useParcelAnalyzeQuery } from "@/lib/site-finder-api";
import type {
  ParcelAnalysis,
  PendingConceptProgram,
} from "@/types/site-finder";

// ── Props ─────────────────────────────────────────────────────────────────────

interface Props {
  cad: string;
}

// ── Page Content (client — needs TanStack Query) ───────────────────────────────

export function AnalysisPageContent({ cad }: Props) {
  const [horizon, setHorizon] = useState<number>(12);
  const queryClient = useQueryClient();

  // «Пересчитать §7 с этой программой» (план #2181, хвост): блок «Как участок
  // сходится» кладёт сюда программу выбранного варианта, §7 «Концепция» её
  // подхватывает (раскрывается + пересчитывает) и зовёт onProgramApplied →
  // обнуляем pending, чтобы повторный клик по тому же варианту снова сработал.
  const [pendingProgram, setPendingProgram] =
    useState<PendingConceptProgram | null>(null);
  // §7 сообщает свой concept.isPending — блок альтернатив дизейблит CTA, пока
  // идёт пересчёт (одна раскладка за раз).
  const [conceptPending, setConceptPending] = useState<boolean>(false);

  const handleApplyToConcept = useCallback(
    (program: PendingConceptProgram) => setPendingProgram(program),
    [],
  );
  const handleProgramApplied = useCallback(() => setPendingProgram(null), []);
  const { data, isLoading, isFetching, error } = useParcelAnalyzeQuery(
    cad,
    horizon,
  );

  // Changing the horizon re-runs /analyze (expensive ~10-30s), which re-enqueues
  // the async §22 forecast (recompute ~30-180s). Invalidating ["parcel-forecast",
  // cad] forces Section 6's poll to re-fetch; until the new run is ready it may
  // still show the previous run's emphasis. The selectedHorizon prop passed to
  // Section6Forecast gives an instant client-side target highlight regardless —
  // that's intended.
  function handleHorizonChange(h: number) {
    setHorizon(h);
    void queryClient.invalidateQueries({ queryKey: ["parcel-forecast", cad] });
  }

  // ── Loading ────────────────────────────────────────────────────────────────

  if (isLoading) {
    return (
      <main style={{ padding: "24px 20px", maxWidth: 1400, margin: "0 auto" }}>
        <Breadcrumb cad={cad} />
        <PageHeading cad={cad} />
        <div
          style={{
            marginTop: 24,
            padding: "40px 24px",
            textAlign: "center",
            color: "var(--fg-tertiary, #73767E)",
            fontSize: 14,
            background: "var(--bg-card-alt, #FAFBFC)",
            border: "1px solid var(--border-soft, #EEF0F3)",
            borderRadius: 12,
          }}
        >
          Анализируем участок {cad}…
        </div>
      </main>
    );
  }

  // ── Error ──────────────────────────────────────────────────────────────────

  if (error || !data) {
    const msg =
      error instanceof Error ? error.message : "Ошибка загрузки анализа";
    return (
      <main style={{ padding: "24px 20px", maxWidth: 1400, margin: "0 auto" }}>
        <Breadcrumb cad={cad} />
        <PageHeading cad={cad} />
        <div
          style={{
            marginTop: 24,
            padding: "16px 20px",
            background: "var(--danger-soft, #FEE2E2)",
            border: "1px solid var(--danger, #B3261E)",
            borderRadius: 12,
            color: "var(--danger, #B3261E)",
            fontSize: 13,
          }}
        >
          {msg}
        </div>
        <div style={{ marginTop: 16 }}>
          <Link
            href="/site-finder"
            style={{
              fontSize: 13,
              color: "var(--accent, #1D4ED8)",
              textDecoration: "none",
            }}
          >
            Вернуться к Site Finder
          </Link>
        </div>
      </main>
    );
  }

  // ── Results layout ─────────────────────────────────────────────────────────

  // Cast to ParcelAnalysis (superset of ParcelAnalyzeResponse) — both describe
  // the same /analyze endpoint; Section3 requires the richer type.
  const analysis = data as unknown as ParcelAnalysis;

  const districtName = analysis.district?.district_name ?? "—";
  // Площадь крошки — из ТОГО ЖЕ источника, что KPI «Площадь» и ЕГРН-таблица в
  // Section1: ЕГРН-area (egrn_block.area_m2 через adaptEgrn), а НЕ geometry-area
  // (geometry_suitability.area_ha считается по геометрии кадастрового квартала и
  // расходится с зарегистрированной площадью участка — давало 6.61 vs 11.68 га).
  const egrnAreaM2 = adaptEgrn(analysis.egrn, cad)?.area_m2;
  const areaStr =
    egrnAreaM2 != null && Number.isFinite(egrnAreaM2) && egrnAreaM2 > 0
      ? `${(egrnAreaM2 / 10000).toFixed(2)} га`
      : null;

  return (
    <main style={{ padding: "24px 20px", maxWidth: 1400, margin: "0 auto" }}>
      {/* Breadcrumb */}
      <Breadcrumb cad={cad} districtName={districtName} areaStr={areaStr} />

      <PageHeading cad={cad} districtName={districtName} />

      {/* Controls row — horizon selector drives the analyze + forecast queries */}
      <div
        style={{
          display: "flex",
          justifyContent: "flex-end",
          alignItems: "center",
          marginTop: 16,
          gap: 12,
        }}
      >
        <HorizonSelector
          value={horizon}
          onChange={handleHorizonChange}
          disabled={isFetching}
        />
      </div>

      {/* Page layout: sidebar (240px) + main scroll. На планшете/телефоне
          .gd-grid-sidebar схлопывает грид в одну колонку (issue #66). */}
      <div
        className="gd-grid-sidebar"
        style={{
          display: "grid",
          gridTemplateColumns: "240px 1fr",
          gap: 24,
          marginTop: 20,
          alignItems: "start",
        }}
      >
        {/* ── Sidebar nav ───────────────────────────────────────────────── */}
        <aside
          className="gd-sidebar"
          style={{
            position: "sticky",
            top: 72,
            alignSelf: "start",
          }}
        >
          <AnalysisSidebarNav
            hasAlternatives={
              (analysis.program_alternatives?.variants?.length ?? 0) > 0
            }
          />
        </aside>

        {/* ── Main scroll area ──────────────────────────────────────────── */}
        <div style={{ display: "flex", flexDirection: "column", gap: 32 }}>
          {/* Вердикт-баннер участка — выше всех секций (#1741). */}
          <GateVerdictBanner verdict={analysis.gate_verdict} />

          {/* ── Группа «Участок» ──────────────────────────────────────── */}
          <GroupDivider label="Участок" />

          {/* 1. Информация — IMPLEMENTED in A5 */}
          <Section1ParcelInfo cad={cad} />

          {/* 2. Оценка участка — IMPLEMENTED in A10 */}
          <Section4Estimate cad={cad} />

          {/* 3. Сети и точки подключения — IMPLEMENTED in A6 */}
          <Section2NetworksUtilities cad={cad} />

          {/* ── Группа «Стройка и рынок» ──────────────────────────────── */}
          <GroupDivider label="Стройка и рынок" />

          {/* 4. Рынок и конкуренты — IMPLEMENTED in A7 */}
          <Section3SettingsAndCompetitors cad={cad} data={analysis} />

          {/* 5. Атмосфера — IMPLEMENTED in A11 */}
          <Section5Atmosphere cad={cad} />

          {/* Статус пересчёта прогноза при смене горизонта (#1744) —
              нейтральная серая строка вместо молчаливого disabled. */}
          {isFetching && (
            <div
              role="status"
              aria-live="polite"
              style={{
                fontSize: 13,
                lineHeight: "20px",
                color: "var(--fg-tertiary, #73767E)",
                transition: "opacity 0.2s",
              }}
            >
              Пересчитываем прогноз на {horizon} мес…
            </div>
          )}

          {/* 6. Прогноз и рекомендация — IMPLEMENTED in 958-B3 (§22 forecast).
              permits_nearby (#2367) приходит из /analyze (не из forecast-
              эндпоинта, который Section6Forecast self-fetch'ит) — прокидываем. */}
          <Section6Forecast
            cad={cad}
            selectedHorizon={horizon}
            permitsNearby={analysis.permits_nearby}
          />

          {/* 7. Концепция — генеративный дизайн застройки (#1965 Stage 1).
              Seeded из анализа (geom + financial_estimate), считается по
              запросу; result lazy-mounted (Leaflet). */}
          <Section7Concept
            analysis={analysis}
            pendingProgram={pendingProgram}
            onProgramApplied={handleProgramApplied}
            onPendingChange={setConceptPending}
          />

          {/* «Как участок сходится» (#2181) — авто-ранжир вариантов программы
              (класс × этажность) по NPV при отрицательном фин-вердикте. Backend
              кладёт program_alternatives только тогда; иначе блок не рендерится.
              Не дубль §7: без карт/3D, статичный топ-3. Кнопка «Пересчитать §7 с
              этой программой» (хвост #2181) прокидывает вариант в §7. */}
          <SectionAlternatives
            alternatives={analysis.program_alternatives}
            onApplyToConcept={handleApplyToConcept}
            conceptPending={conceptPending}
          />
        </div>
      </div>

      {/* Chat — grounded parcel-chat over the §22 forecast (#958). Docked
          right-side floating panel (position: fixed), доступен при любом
          скролле; mount once, placement in the tree is irrelevant. */}
      <ChatDock cadNum={cad} />
    </main>
  );
}

// ── Page heading (h1 a11y) ─────────────────────────────────────────────────────
//
// Единственный <h1> страницы анализа (#1926 a11y): присутствует во ВСЕХ состояниях
// (loading / error / success), не только в success — иначе SR-пользователь на этапе
// загрузки/ошибки остаётся без заголовка верхнего уровня. district дописывается
// когда известен (success). Стиль = h1-токен (22/28 weight 600, left-align).

function PageHeading({
  cad,
  districtName,
}: {
  cad: string;
  districtName?: string;
}) {
  const hasDistrict = districtName != null && districtName !== "—";
  return (
    <h1
      style={{
        fontSize: 22,
        fontWeight: 600,
        margin: "12px 0 0",
        color: "var(--fg-primary, #111111)",
      }}
    >
      Анализ участка {cad}
      {hasDistrict ? ` · ${districtName}` : ""}
    </h1>
  );
}

// ── Breadcrumb ─────────────────────────────────────────────────────────────────

function Breadcrumb({
  cad,
  districtName,
  areaStr,
}: {
  cad: string;
  districtName?: string;
  areaStr?: string | null;
}) {
  const parts = [cad];
  if (districtName && districtName !== "—") parts.push(districtName);
  if (areaStr) parts.push(areaStr);

  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        gap: 8,
        fontSize: 13,
        color: "var(--fg-secondary, #5B6066)",
      }}
    >
      <Link
        href="/site-finder"
        style={{
          color: "var(--accent, #1D4ED8)",
          textDecoration: "none",
          fontWeight: 500,
        }}
      >
        Site Finder
      </Link>
      <span style={{ color: "var(--fg-tertiary, #73767E)" }}>/</span>
      {parts.map((part, i) => (
        <span key={i}>
          {i > 0 && (
            <span
              style={{
                margin: "0 6px",
                color: "var(--fg-tertiary, #73767E)",
              }}
            >
              &middot;
            </span>
          )}
          {part}
        </span>
      ))}
      <span style={{ margin: "0 4px", color: "var(--fg-tertiary, #73767E)" }}>
        &middot;
      </span>
      <span style={{ color: "var(--fg-tertiary, #73767E)" }}>анализ</span>
    </div>
  );
}

// ── Group divider ────────────────────────────────────────────────────────────
//
// Плашка-разделитель между смысловыми группами секций (#1741): тёмный фон
// --bg-headline + светлый uppercase-label --fg-on-dark, паттерн headline-bar.

function GroupDivider({ label }: { label: string }) {
  return (
    <div
      style={{
        background: "var(--bg-headline, #0F172A)",
        borderRadius: 12,
        padding: "10px 18px",
      }}
    >
      <div
        style={{
          fontSize: 12,
          fontWeight: 600,
          letterSpacing: "0.06em",
          textTransform: "uppercase",
          color: "var(--fg-on-dark, #E2E8F0)",
        }}
      >
        {label}
      </div>
    </div>
  );
}

// ── Sidebar nav ────────────────────────────────────────────────────────────────
//
// Две группы с групп-хедерами (#1741). Нумерация секций сквозная 1–6 под новый
// порядок: «Участок» → 1-3, «Стройка и рынок» → 4-6.

interface NavItem {
  id: string;
  label: string;
  children?: { id: string; label: string }[];
}

interface NavGroup {
  label: string;
  items: NavItem[];
}

const NAV_GROUPS: NavGroup[] = [
  {
    label: "Участок",
    items: [
      { id: "section-1", label: "1. Информация" },
      { id: "section-4", label: "2. Оценка участка" },
      { id: "section-2", label: "3. Сети и точки подключения" },
    ],
  },
  {
    label: "Стройка и рынок",
    items: [
      {
        id: "section-3",
        label: "4. Рынок и конкуренты",
        children: [
          { id: "section-3-1", label: "4.1 Настройки выборки" },
          { id: "section-3-2", label: "4.2 Планировки" },
          { id: "section-3-3", label: "4.3 Остатки и скорость" },
        ],
      },
      { id: "section-5", label: "5. Атмосфера" },
      {
        id: "section-6",
        label: "6. Прогноз и рекомендация",
        children: [
          { id: "section-6-1", label: "6.1 Прогноз по горизонтам" },
          { id: "section-6-2", label: "6.2 Сценарии" },
          { id: "section-6-3", label: "6.3 Уверенность" },
          { id: "section-6-4", label: "6.4 Рекомендация по продукту" },
          { id: "section-6-5", label: "6.5 Прозрачность скоринга" },
          { id: "section-6-6", label: "6.6 Будущее предложение и конкуренты" },
        ],
      },
      { id: "section-7", label: "7. Концепция" },
    ],
  },
];

// «Альтернативы» (#2181) — навигационный пункт для блока «Как участок сходится».
// Добавляется в конец группы «Стройка и рынок» ТОЛЬКО когда backend вернул
// program_alternatives (иначе якоря section-alternatives на странице нет).
const ALTERNATIVES_NAV_ITEM: NavItem = {
  id: "section-alternatives",
  label: "Альтернативы программы",
};

/** NAV_GROUPS с опциональным пунктом «Альтернативы» в хвосте (#2181). */
function buildNavGroups(hasAlternatives: boolean): NavGroup[] {
  if (!hasAlternatives) return NAV_GROUPS;
  return NAV_GROUPS.map((g) =>
    g.label === "Стройка и рынок"
      ? { ...g, items: [...g.items, ALTERNATIVES_NAV_ITEM] }
      : g,
  );
}

// Sticky chrome offset (header + breadcrumb). The jump lands the section title
// just below this; the scrollspy uses the same line to pick the active section.
const SCROLL_OFFSET = 80;

// Jump to a section. behavior:"auto" (INSTANT), NOT smooth: on this heavy report
// (Leaflet maps, async §6 forecast, lazy charts) the continuous reflow silently
// cancels a smooth window.scrollTo — it never moved («навигация не прыгает»).
// Instant is reliable and reads as a real jump. Absolute document target +
// SCROLL_OFFSET clears the sticky chrome and is robust to async height shifts.
function scrollToSection(id: string) {
  const el = document.getElementById(id);
  if (!el) return;
  const top = el.getBoundingClientRect().top + window.scrollY - SCROLL_OFFSET;
  window.scrollTo({ top, behavior: "auto" });
}

function AnalysisSidebarNav({
  hasAlternatives = false,
}: {
  hasAlternatives?: boolean;
}) {
  const navGroups = useMemo(
    () => buildNavGroups(hasAlternatives),
    [hasAlternatives],
  );
  // Top-level section anchors in scroll order — observed by the scrollspy.
  // Children (3.x / 6.x) are intentionally NOT observed: their parent stays lit
  // while the user is anywhere inside the section, which reads cleaner. Rebuilt
  // only when «Альтернативы» (#2181) appears/disappears so the effect's dep is
  // stable (not a fresh array each render).
  const topLevelIds = useMemo(
    () => navGroups.flatMap((g) => g.items.map((i) => i.id)),
    [navGroups],
  );

  // Scrollspy: the active section is the LAST one whose top has scrolled past the
  // offset line (deterministic, never "empty" — unlike a narrow IntersectionObserver
  // band, which left the last/at-bottom section un-lit). Default to the first so
  // something is lit before any scroll.
  const [activeId, setActiveId] = useState<string>(topLevelIds[0]);

  useEffect(() => {
    if (typeof window === "undefined") return;

    let raf = 0;
    const compute = () => {
      raf = 0;
      // At the page bottom the last section can be too short to reach the offset
      // line — force it active so the last nav item lights up. (2px tolerance.)
      const atBottom =
        window.innerHeight + window.scrollY >=
        document.documentElement.scrollHeight - 2;
      if (atBottom) {
        setActiveId(topLevelIds[topLevelIds.length - 1]);
        return;
      }
      // Otherwise: the last section whose top has passed the offset line.
      let current = topLevelIds[0];
      for (const id of topLevelIds) {
        const el = document.getElementById(id);
        if (el && el.getBoundingClientRect().top - SCROLL_OFFSET <= 1) {
          current = id;
        }
      }
      setActiveId(current);
    };
    // rAF-throttle: at most one O(7) measurement per frame, never mid-frame jank.
    const onScroll = () => {
      if (raf) return;
      raf = window.requestAnimationFrame(compute);
    };

    window.addEventListener("scroll", onScroll, { passive: true });
    compute(); // initial state

    return () => {
      window.removeEventListener("scroll", onScroll);
      if (raf) window.cancelAnimationFrame(raf);
    };
  }, [topLevelIds]);

  return (
    <nav
      className="gd-section-nav"
      style={{
        background: "var(--bg-card, #FFFFFF)",
        border: "1px solid var(--border-card, #E6E8EC)",
        borderRadius: 12,
        padding: "12px 0",
        display: "flex",
        flexDirection: "column",
      }}
    >
      {navGroups.map((group, gi) => (
        <div key={group.label}>
          <div
            style={{
              padding: gi === 0 ? "0 16px 6px" : "12px 16px 6px",
              fontSize: 11,
              fontWeight: 600,
              letterSpacing: "0.06em",
              textTransform: "uppercase",
              color: "var(--fg-tertiary, #73767E)",
            }}
          >
            {group.label}
          </div>
          {group.items.map((item) => {
            const isActive = activeId === item.id;
            return (
              <div key={item.id}>
                <button
                  type="button"
                  onClick={() => scrollToSection(item.id)}
                  aria-current={isActive ? "true" : undefined}
                  style={{
                    display: "block",
                    width: "100%",
                    textAlign: "left",
                    padding: "8px 16px",
                    background: isActive
                      ? "var(--accent-soft, #DBEAFE)"
                      : "none",
                    border: "none",
                    borderLeft: isActive
                      ? "3px solid var(--accent, #1D4ED8)"
                      : "3px solid transparent",
                    cursor: "pointer",
                    fontSize: 13,
                    fontWeight: isActive ? 600 : 500,
                    color: isActive
                      ? "var(--accent, #1D4ED8)"
                      : "var(--fg-primary, #111111)",
                    transition: "background 0.1s, color 0.1s",
                  }}
                  onMouseEnter={(e) => {
                    if (!isActive) {
                      e.currentTarget.style.background =
                        "var(--bg-card-alt, #FAFBFC)";
                    }
                  }}
                  onMouseLeave={(e) => {
                    if (!isActive) e.currentTarget.style.background = "none";
                  }}
                >
                  {item.label}
                </button>
                {item.children?.map((child) => (
                  <button
                    key={child.id}
                    type="button"
                    onClick={() => scrollToSection(child.id)}
                    style={{
                      display: "block",
                      width: "100%",
                      textAlign: "left",
                      padding: "6px 16px 6px 28px",
                      background: "none",
                      border: "none",
                      cursor: "pointer",
                      fontSize: 12,
                      color: "var(--fg-secondary, #5B6066)",
                      transition: "background 0.1s",
                    }}
                    onMouseEnter={(e) => {
                      e.currentTarget.style.background =
                        "var(--bg-card-alt, #FAFBFC)";
                    }}
                    onMouseLeave={(e) => {
                      e.currentTarget.style.background = "none";
                    }}
                  >
                    {child.label}
                  </button>
                ))}
              </div>
            );
          })}
        </div>
      ))}
    </nav>
  );
}

// ── Section placeholder ────────────────────────────────────────────────────────

function SectionPlaceholder({
  number,
  title,
  note,
}: {
  number: string;
  title: string;
  note: string;
}) {
  return (
    <>
      <div
        style={{
          background: "var(--bg-headline, #0F172A)",
          borderRadius: 12,
          padding: "14px 18px",
          marginBottom: 12,
        }}
      >
        <div
          style={{
            fontSize: 15,
            fontWeight: 600,
            color: "var(--fg-on-dark, #E2E8F0)",
          }}
        >
          {number}. {title}
        </div>
      </div>
      <div
        style={{
          background: "var(--bg-card-alt, #FAFBFC)",
          border: "1px dashed var(--border-strong, #D1D5DB)",
          borderRadius: 12,
          padding: "32px 24px",
          textAlign: "center",
          color: "var(--fg-tertiary, #73767E)",
          fontSize: 13,
        }}
      >
        {note}
      </div>
    </>
  );
}
