import { render } from "@testing-library/react";
import { vi } from "vitest";

import type { ObjectSaleGraphPoint } from "@/types/analytics";

// Capture the ECharts `option` passed to ChartShell instead of mounting the
// (SSR-disabled, heavy) ReactECharts dynamic import.
const lastOption: { current: Record<string, unknown> | null } = { current: null };
vi.mock("../ChartShell", () => ({
  ChartShell: ({ option }: { option: Record<string, unknown> }) => {
    lastOption.current = option;
    return null;
  },
}));

const useObjectSaleGraph = vi.fn();
vi.mock("@/lib/analytics-api", () => ({
  useObjectSaleGraph: (objId: number | string) => useObjectSaleGraph(objId),
}));

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

interface Series {
  name: string;
  type: string;
  data: (number | null)[];
}

function renderWith(points: ObjectSaleGraphPoint[]) {
  useObjectSaleGraph.mockReturnValue({ data: points, isLoading: false });
  lastOption.current = null;
  render(<ObjectSaleChart objId={1} />);
  expect(lastOption.current).not.toBeNull();
  const opt = lastOption.current as unknown as {
    xAxis: { data: string[] };
    series: Series[];
  };
  const seriesByName = Object.fromEntries(
    opt.series.map((s) => [s.name, s.data]),
  );
  return { months: opt.xAxis.data, seriesByName };
}

function pt(
  type: string,
  report_month: string,
  realised: number,
  price_avg: number | null,
): ObjectSaleGraphPoint {
  return {
    type,
    report_month,
    realised,
    contracted: realised,
    area_sq: null,
    price_avg,
  };
}

describe("ObjectSaleChart", () => {
  it("builds X axis from the union of all types' months, sorted", () => {
    // apartments: May–Jul; parking starts later (Jun–Aug) — divergent sets.
    const { months } = renderWith([
      pt("apartments", "2025-05-01", 5, 100000),
      pt("apartments", "2025-06-01", 6, 110000),
      pt("apartments", "2025-07-01", 7, 120000),
      pt("parking", "2025-06-01", 1, 50000),
      pt("parking", "2025-07-01", 2, 51000),
      pt("parking", "2025-08-01", 3, 52000),
    ]);
    expect(months).toEqual([
      "2025-05",
      "2025-06",
      "2025-07",
      "2025-08",
    ]);
  });

  it("aligns each series to the union axis by month, null where absent", () => {
    const { seriesByName } = renderWith([
      pt("apartments", "2025-05-01", 5, 100000),
      pt("apartments", "2025-06-01", 6, 110000),
      pt("apartments", "2025-07-01", 7, 120000),
      pt("parking", "2025-06-01", 1, 50000),
      pt("parking", "2025-07-01", 2, 51000),
      pt("parking", "2025-08-01", 3, 52000),
    ]);
    // apartments has no Aug → null in the last slot; parking has no May → null first.
    expect(seriesByName["apartments · реализовано"]).toEqual([5, 6, 7, null]);
    expect(seriesByName["parking · реализовано"]).toEqual([null, 1, 2, 3]);
    // Price line aligned identically (rounded), null where the type has no month.
    expect(seriesByName["apartments · цена ₽/м²"]).toEqual([
      100000,
      110000,
      120000,
      null,
    ]);
    expect(seriesByName["parking · цена ₽/м²"]).toEqual([
      null,
      50000,
      51000,
      52000,
    ]);
  });

  it("does not silently drop a later type's extra months (regression)", () => {
    // First type (apartments, sorts first) has FEWER months than parking —
    // the old positional code would have clipped parking's extra tail.
    const { months, seriesByName } = renderWith([
      pt("apartments", "2025-05-01", 5, 100000),
      pt("parking", "2025-05-01", 1, 50000),
      pt("parking", "2025-06-01", 2, 51000),
      pt("parking", "2025-07-01", 3, 52000),
    ]);
    expect(months).toEqual(["2025-05", "2025-06", "2025-07"]);
    expect(seriesByName["parking · реализовано"]).toEqual([1, 2, 3]);
    expect(seriesByName["apartments · реализовано"]).toEqual([5, null, null]);
  });

  it("keeps happy-path (identical months) unchanged", () => {
    // Current prod reality: every type shares the same month grid.
    const { months, seriesByName } = renderWith([
      pt("apartments", "2025-05-01", 5, 100000),
      pt("apartments", "2025-06-01", 6, 110000),
      pt("parking", "2025-05-01", 1, 50000),
      pt("parking", "2025-06-01", 2, 51000),
    ]);
    expect(months).toEqual(["2025-05", "2025-06"]);
    expect(seriesByName["apartments · реализовано"]).toEqual([5, 6]);
    expect(seriesByName["parking · реализовано"]).toEqual([1, 2]);
    expect(seriesByName["apartments · цена ₽/м²"]).toEqual([100000, 110000]);
  });

  it("shows empty-state title when there are no points", () => {
    useObjectSaleGraph.mockReturnValue({ data: [], isLoading: false });
    lastOption.current = null;
    render(<ObjectSaleChart objId={1} />);
    const opt = lastOption.current as unknown as {
      title?: { text: string };
    };
    expect(opt.title?.text).toBe("Нет данных по продажам");
  });
});
