import {
  cleanup,
  fireEvent,
  render,
  screen,
  waitFor,
} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { createRef } from "react";
import assert from "node:assert";
import {
  afterEach,
  describe,
  mock,
  test,
} from "node:test";
import { MapPanel } from "./MapPanel";
import { MapContext } from "../context";

const Inner = ({ data }: { data?: { id?: string; }; }) => <div data-testid={"panel-content"}>{data?.id ?? ""}</div>;

const getContextValue = ({
  panelData = null,
  onAction = null,
}: {
  panelData?: unknown;
  onAction?: unknown;
}) => ({
  getCN: (_el: string) => "",
  instanceRef: createRef(),
  containerRef: createRef(),
  balloonRef: createRef(),
  maxActivePoints: 1,
  modules: {},
  zoom: 10,
  options: {},
  api: {
    load: [],
    key: "",
  },
  currentClusters: [],
  clusters: [],
  panelData,
  onAction,
  stateActions: {
    setIsDisabled: () => {},
    setClusters: () => {},
    setPanelData: () => {},
    setPointState: () => {},
  },
});

describe("MapPanel", () => {
  afterEach(() => {
    cleanup();
  });

  test("opens when panelData is provided", async () => {
    const onAction = mock.fn();

    const { rerender } = render(
      <MapContext value={getContextValue({ onAction }) as unknown}>
        <MapPanel>
          <Inner />
        </MapPanel>
      </MapContext>
    );

    assert.strictEqual(screen.queryByTestId("panel-content"), null);

    rerender(
      <MapContext value={getContextValue({
        onAction,
        panelData: {
          id: "point-1",
          coords: [ 55.751244, 37.618423 ],
          meta: {},
        },
      }) as unknown}>
        <MapPanel>
          <Inner />
        </MapPanel>
      </MapContext>
    );

    await waitFor(() => {
      assert.notStrictEqual(screen.queryByTestId("panel-content"), null);
      assert.strictEqual(screen.getByTestId("panel-content").textContent, "point-1");
      assert.strictEqual(
        onAction.mock.calls.some((call) => call.arguments?.[0]?.getData?.()?.type === "panelOpen"), true
      );
    });
  });

  test("closes on close button click", async () => {
    const user = userEvent.setup();
    const onAction = mock.fn();

    const { rerender } = render(
      <MapContext value={getContextValue({ onAction }) as unknown}>
        <MapPanel>
          <Inner />
        </MapPanel>
      </MapContext>
    );

    rerender(
      <MapContext value={getContextValue({
        onAction,
        panelData: {
          id: "point-1",
          coords: [ 55.751244, 37.618423 ],
          meta: {},
        },
      }) as unknown}>
        <MapPanel>
          <Inner />
        </MapPanel>
      </MapContext>
    );

    await waitFor(() => {
      assert.notStrictEqual(screen.queryByTestId("panel-content"), null);
    });

    await user.click(screen.getByRole("button"));

    const panelNode = screen.queryByTestId("panel-content")?.closest("aside") as HTMLElement | null;
    assert.notStrictEqual(panelNode, null);
    fireEvent.transitionEnd(panelNode as HTMLElement);

    await waitFor(() => {
      assert.strictEqual(screen.queryByTestId("panel-content"), null);
      assert.strictEqual(
        onAction.mock.calls.some((call) => call.arguments?.[0]?.getData?.()?.type === "panelClose"), true
      );
    });
  });
});
