import { act, 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 { ToolcraftExternalStore } from "../../../state/toolcraft-external-store";
import { ToolcraftRoot } from "../../app-shell/toolcraft-root";
import { useToolcraftStore } from "../../app-shell/toolcraft-store-context";
import type { ToolcraftCustomControlRendererProps } from "../control-renderers";
import { ControlsPanel } from "../controls-panel";

const extensionsSchema = defineToolcraft({
  canvas: { enabled: true },
  panels: {
    controls: {
      sections: [
        {
          controls: {
            title: {
              defaultValue: "Built in",
              target: "document.title",
              type: "text",
            },
            live: {
              defaultValue: 10,
              label: "Live",
              target: "document.live",
              type: "liveCustom",
            },
            export: {
              actions: [{ label: "Export", value: "export" }],
              target: "panel.actions",
              type: "panelActions",
            },
          },
          title: "Extensions",
        },
      ],
      title: "Controls",
    },
  },
});

function CaptureStore({
  capture,
}: {
  capture: (store: ToolcraftExternalStore) => void;
}): null {
  capture(useToolcraftStore());
  return null;
}

afterEach(() => {
  cleanup();
  vi.restoreAllMocks();
});

describe("ControlsPanel extension live state", () => {
  it("keeps built-in structure cold while a custom renderer receives effective state", () => {
    const renderCustom = vi.fn(
      ({ state, value }: ToolcraftCustomControlRendererProps) => (
        <output data-testid="live-custom-state">
          {state.timeline.currentTimeSeconds}:{state.canvas.offset.x}:
          {state.canvas.offset.y}:{state.canvas.zoom}:{String(value)}
        </output>
      ),
    );
    let store: ToolcraftExternalStore | undefined;

    render(
      <ToolcraftRoot schema={extensionsSchema}>
        <ControlsPanel
          controlRenderers={{ liveCustom: renderCustom }}
          framed={false}
        />
        <CaptureStore capture={(value) => { store = value; }} />
      </ToolcraftRoot>,
    );
    const builtInInput = screen.getByDisplayValue("Built in");
    const initialCustomRenders = renderCustom.mock.calls.length;

    act(() => {
      store?.dispatchTransient({
        currentTimeSeconds: 3,
        type: "timeline.setCurrentTime",
      });
      store?.dispatchTransient({
        offset: { x: 24, y: -12 },
        type: "canvas.setViewport",
        zoom: 150,
      });
    });

    expect(screen.getByDisplayValue("Built in")).toBe(builtInInput);
    expect(screen.getByTestId("live-custom-state").textContent).toBe(
      "3:24:-12:150:10",
    );
    expect(renderCustom.mock.calls.length).toBeGreaterThan(initialCustomRenders);
  });

  it("reads effective state when an app action starts", () => {
    const onPanelAction = vi.fn();
    let store: ToolcraftExternalStore | undefined;

    render(
      <ToolcraftRoot schema={extensionsSchema}>
        <ControlsPanel
          framed={false}
          onPanelAction={onPanelAction}
        />
        <CaptureStore capture={(value) => { store = value; }} />
      </ToolcraftRoot>,
    );
    act(() => {
      store?.dispatchTransient({
        currentTimeSeconds: 2.5,
        type: "timeline.setCurrentTime",
      });
      store?.dispatchTransient({
        offset: { x: 18, y: -9 },
        type: "canvas.setViewport",
        zoom: 125,
      });
    });

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

    const actionState = onPanelAction.mock.calls[0]?.[0].state;
    expect(actionState.timeline.currentTimeSeconds).toBe(2.5);
    expect(actionState.canvas).toMatchObject({
      offset: { x: 18, y: -9 },
      zoom: 125,
    });
  });
});
