import { cleanup, fireEvent, render, screen } from "@testing-library/react";
import * as React from "react";
import { afterEach, describe, expect, it, vi } from "vitest";

import { defineToolcraft } from "../../schema/define-toolcraft";
import type { ToolcraftPanelState } from "../../state/types";
import { ToolcraftRoot } from "../app-shell/toolcraft-root";
import { useToolcraft } from "../app-shell/use-toolcraft";
import { useToolcraftPanelBinding } from "./use-toolcraft-panel-binding";

const schema = defineToolcraft({
  canvas: { enabled: true },
  panels: {
    controls: {
      sections: [
        {
          controls: {
            opacity: {
              defaultValue: 75,
              target: "appearance.opacity",
              type: "slider",
            },
          },
          id: "appearance",
          title: "Appearance",
        },
      ],
      title: "Controls",
    },
  },
});

afterEach(() => {
  cleanup();
  window.localStorage.clear();
});

function PanelBindingProbe({
  onPanelStateChange,
  panelState,
}: {
  onPanelStateChange?: (patch: Partial<ToolcraftPanelState>) => void;
  panelState?: ToolcraftPanelState;
}): React.JSX.Element {
  const { dispatch, state } = useToolcraft();
  const binding = useToolcraftPanelBinding({
    onPanelStateChange,
    panelId: "controls",
    panelState,
  });

  return (
    <>
      <button
        onClick={() =>
          binding.onPanelStateChange({
            collapsed: true,
            offset: { x: 64, y: 32 },
            snapEdge: "right",
          })
        }
        type="button"
      >
        Commit placement
      </button>
      <button
        onClick={() =>
          dispatch({
            collapsed: true,
            sectionId: "appearance",
            type: "panels.setSectionCollapsed",
          })
        }
        type="button"
      >
        Collapse appearance
      </button>
      <output data-testid="bound-panel-state">
        {JSON.stringify(binding.panelState)}
      </output>
      <output data-testid="runtime-panel-state">
        {JSON.stringify(state.panels.controls)}
      </output>
      <output data-testid="history-count">{state.history.undo.length}</output>
    </>
  );
}

describe("useToolcraftPanelBinding", () => {
  it("binds panel changes to committed runtime state without history", () => {
    render(
      <ToolcraftRoot schema={schema}>
        <PanelBindingProbe />
      </ToolcraftRoot>,
    );

    fireEvent.click(screen.getByRole("button", { name: "Commit placement" }));

    expect(JSON.parse(screen.getByTestId("runtime-panel-state").textContent ?? "{}"))
      .toMatchObject({
        collapsed: true,
        offset: { x: 64, y: 32 },
        snapEdge: "right",
      });
    expect(screen.getByTestId("history-count").textContent).toBe("0");
  });

  it("keeps deliberately controlled state authoritative", () => {
    const onPanelStateChange = vi.fn();
    const controlledState: ToolcraftPanelState = {
      collapsed: false,
      offset: { x: 12, y: 18 },
      snapEdge: "left",
    };

    render(
      <ToolcraftRoot schema={schema}>
        <PanelBindingProbe
          onPanelStateChange={onPanelStateChange}
          panelState={controlledState}
        />
      </ToolcraftRoot>,
    );

    fireEvent.click(screen.getByRole("button", { name: "Commit placement" }));

    expect(onPanelStateChange).toHaveBeenCalledWith({
      collapsed: true,
      offset: { x: 64, y: 32 },
      snapEdge: "right",
    });
    expect(JSON.parse(screen.getByTestId("bound-panel-state").textContent ?? "{}"))
      .toEqual({ ...controlledState, collapsedSections: {} });
    expect(JSON.parse(screen.getByTestId("runtime-panel-state").textContent ?? "{}"))
      .toMatchObject({ offset: { x: 0, y: 0 } });
  });

  it("keeps controls-specific runtime state alongside controlled base fields", () => {
    const controlledState: ToolcraftPanelState = {
      collapsed: false,
      offset: { x: 12, y: 18 },
      snapEdge: "left",
    };

    render(
      <ToolcraftRoot schema={schema}>
        <PanelBindingProbe panelState={controlledState} />
      </ToolcraftRoot>,
    );

    fireEvent.click(screen.getByRole("button", { name: "Collapse appearance" }));

    expect(JSON.parse(screen.getByTestId("bound-panel-state").textContent ?? "{}"))
      .toEqual({
        collapsed: false,
        collapsedSections: { appearance: true },
        offset: { x: 12, y: 18 },
        snapEdge: "left",
      });
  });
});
