import { fireEvent, render, screen } from "@testing-library/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { describe, expect, it, vi } from "vitest";

import { AnalysisPageContent } from "../AnalysisPageContent";

// ── Regression test: epic #2445 item B4 ──────────────────────────────────────
//
// Bug: AnalysisPageContent (and its §7 Section7Concept child) was rendered
// without a React `key` tied to `cad`. Client-side nav between two different
// parcels under the SAME /site-finder/analysis/[cad] route template (e.g.
// RecentParcels / CompareTable → plain next/link to a different cad) reused
// the same component instance — instance-local state (§7's useCreateConcept
// mutation result, which has no cache key: it lives only in
// concept.data/isSuccess/isError) kept showing the OLD parcel's computed
// concept until the user manually re-ran it.
//
// Fix: page.tsx now renders <AnalysisPageContent key={cad} cad={cad} /> so a
// parcel change forces a clean remount. This test exercises that exact
// pattern (rendering AnalysisPageContent keyed by cad, same as page.tsx) and
// asserts:
//   1. Same cad, re-render → local state in a §7-like child is PRESERVED
//      (normal interaction, e.g. horizon change, must not lose progress).
//   2. Different cad → local state RESETS (remount), instead of leaking the
//      previous parcel's concept into the new parcel's view.
//
// The real §7Concept/useCreateConcept + all sibling sections pull in Leaflet/
// ECharts/TanStack Query fetches — irrelevant to the remount contract under
// test — so every section is mocked with a light stub. The Section7Concept
// stub mirrors the real bug shape: a plain useState "concept result" with NO
// cad-keyed cache, set via a button click (stand-in for the mutation firing).

vi.mock("@/lib/site-finder-api", async () => {
  const actual = await vi.importActual<typeof import("@/lib/site-finder-api")>(
    "@/lib/site-finder-api",
  );
  return {
    ...actual,
    useParcelAnalyzeQuery: (cad: string) => ({
      data: { district: null, egrn: null, gate_verdict: null, cad },
      isLoading: false,
      isFetching: false,
      error: null,
    }),
  };
});

vi.mock("@/components/site-finder/ChatDock", () => ({
  ChatDock: () => null,
}));
vi.mock("@/components/site-finder/GateVerdictBanner", () => ({
  GateVerdictBanner: () => null,
}));
vi.mock("@/components/site-finder/HorizonSelector", () => ({
  HorizonSelector: () => null,
}));
vi.mock("@/components/site-finder/analysis/Section1ParcelInfo", () => ({
  Section1ParcelInfo: () => null,
}));
vi.mock("@/components/site-finder/analysis/Section2NetworksUtilities", () => ({
  Section2NetworksUtilities: () => null,
}));
vi.mock(
  "@/components/site-finder/analysis/Section3SettingsAndCompetitors",
  () => ({ Section3SettingsAndCompetitors: () => null }),
);
vi.mock("@/components/site-finder/analysis/Section4Estimate", () => ({
  Section4Estimate: () => null,
}));
vi.mock("@/components/site-finder/analysis/Section5Atmosphere", () => ({
  Section5Atmosphere: () => null,
}));
vi.mock("@/components/site-finder/analysis/Section6Forecast", () => ({
  Section6Forecast: () => null,
}));
vi.mock("@/components/site-finder/analysis/SectionAlternatives", () => ({
  SectionAlternatives: () => null,
}));

// Stub §7: a plain useState "concept" with no cad-keyed cache — the exact
// shape of the real useCreateConcept()-backed bug. A button click simulates
// the mutation firing and settling.
vi.mock("@/components/site-finder/analysis/Section7Concept", () => {
  const React = require("react") as typeof import("react");
  return {
    Section7Concept: () => {
      const [concept, setConcept] = React.useState<string | null>(null);
      return (
        <div>
          <button type="button" onClick={() => setConcept("computed-concept")}>
            Сгенерировать концепцию
          </button>
          <div data-testid="concept-state">{concept ?? "empty"}</div>
        </div>
      );
    },
  };
});

// AnalysisPageContent calls useQueryClient() directly (horizon-change
// invalidation) even though useParcelAnalyzeQuery is mocked above, so every
// render needs a real QueryClientProvider ancestor.
function renderKeyed(cad: string) {
  const client = new QueryClient();
  return render(
    <QueryClientProvider client={client}>
      <AnalysisPageContent key={cad} cad={cad} />
    </QueryClientProvider>,
  );
}

describe("AnalysisPageContent — key={cad} remount contract (#2445 B4)", () => {
  it("preserves §7-like local state across a re-render with the SAME cad", () => {
    const client = new QueryClient();
    const cad = "66:41:0204016:10";
    const { rerender } = render(
      <QueryClientProvider client={client}>
        <AnalysisPageContent key={cad} cad={cad} />
      </QueryClientProvider>,
    );

    fireEvent.click(
      screen.getByRole("button", { name: "Сгенерировать концепцию" }),
    );
    expect(screen.getByTestId("concept-state").textContent).toBe(
      "computed-concept",
    );

    // Same cad → same key → React must NOT remount; in-progress state stays
    // (e.g. a horizon change re-renders the same tree — must not lose it).
    rerender(
      <QueryClientProvider client={client}>
        <AnalysisPageContent key={cad} cad={cad} />
      </QueryClientProvider>,
    );
    expect(screen.getByTestId("concept-state").textContent).toBe(
      "computed-concept",
    );
  });

  it("resets §7-like local state when navigating to a DIFFERENT cad", () => {
    // Single render tree that we rerender() with a CHANGED key — this pins the
    // `key={cad}` mechanism itself. A fresh unmount()+render() would reset state
    // unconditionally (even with no key), so it would pass on a reverted fix and
    // wouldn't guard the regression. With rerender() + changed key, React keeps
    // the tree mounted and only remounts because the key differs — exactly what
    // page.tsx's `key={cad}` does on client-side nav. Drop the key in page.tsx
    // and the OLD instance is reused, leaking "computed-concept" → this fails.
    const client = new QueryClient();
    const { rerender } = render(
      <QueryClientProvider client={client}>
        <AnalysisPageContent key="66:41:0204016:10" cad="66:41:0204016:10" />
      </QueryClientProvider>,
    );

    fireEvent.click(
      screen.getByRole("button", { name: "Сгенерировать концепцию" }),
    );
    expect(screen.getByTestId("concept-state").textContent).toBe(
      "computed-concept",
    );

    // Client-side nav to a different parcel: same tree position, different key.
    rerender(
      <QueryClientProvider client={client}>
        <AnalysisPageContent key="66:41:0702033:20" cad="66:41:0702033:20" />
      </QueryClientProvider>,
    );

    expect(screen.getByTestId("concept-state").textContent).toBe("empty");
  });
});
