import { act, fireEvent, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";

import {
  DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
  getToolcraftOrientationPoseFromPointerDelta,
  readToolcraftOrientationPose,
} from "./orientation-gizmo-math";
import {
  expectOrientationPoseClose,
  mockOrientationGizmoBounds,
  renderOrientationGizmoRuntime,
} from "./orientation-gizmo-test-harness";

describe("Toolcraft orientation gizmo integration", () => {
  it("renders one fixed canvas handle without duplicate panel UI", async () => {
    renderOrientationGizmoRuntime();

    const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo");

    expect(gizmo.getAttribute("data-toolcraft-canvas-handle")).toBe(
      "orientation-gizmo",
    );
    expect(gizmo.style.left).toBe("16px");
    expect(gizmo.style.bottom).toBe("16px");
    expect(screen.getByText("Scale")).toBeTruthy();
    expect(screen.queryByText("Orientation")).toBeNull();
  });

  it("updates live before pointer release through one undoable value gesture", async () => {
    const store = renderOrientationGizmoRuntime();
    const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo");
    mockOrientationGizmoBounds(gizmo);

    fireEvent.pointerDown(gizmo, {
      button: 0,
      clientX: 59.5,
      clientY: 35,
      pointerId: 1,
    });
    fireEvent.pointerMove(gizmo, {
      clientX: 47,
      clientY: 43,
      pointerId: 1,
    });

    expectOrientationPoseClose(
      readToolcraftOrientationPose(store.getState().values["view.orbit"]),
      getToolcraftOrientationPoseFromPointerDelta(
        DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
        -12.5,
        8,
      ),
    );
    fireEvent.pointerUp(gizmo, { pointerId: 1 });

    act(() => {
      store.dispatch({ type: "history.undo" });
    });
    expect(store.getState().values["view.orbit"]).toEqual(
      DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
    );
  });

  it("drags from empty gizmo background and keeps the full threshold delta", async () => {
    const store = renderOrientationGizmoRuntime();
    const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo");
    mockOrientationGizmoBounds(gizmo);

    fireEvent.pointerDown(gizmo, {
      button: 0,
      clientX: 35,
      clientY: 20,
      pointerId: 11,
    });
    fireEvent.pointerMove(gizmo, {
      clientX: 37,
      clientY: 22,
      pointerId: 11,
    });
    expect(store.getState().values["view.orbit"]).toEqual(
      DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
    );
    fireEvent.pointerMove(gizmo, {
      clientX: 39,
      clientY: 24,
      pointerId: 11,
    });
    fireEvent.pointerUp(gizmo, { pointerId: 11 });

    expectOrientationPoseClose(
      readToolcraftOrientationPose(store.getState().values["view.orbit"]),
      getToolcraftOrientationPoseFromPointerDelta(
        DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
        4,
        4,
      ),
    );
    expect(store.getState().history.undo).toHaveLength(1);
  });

  it("keeps an empty-background click inert", async () => {
    const store = renderOrientationGizmoRuntime();
    const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo");
    mockOrientationGizmoBounds(gizmo);

    fireEvent.pointerDown(gizmo, {
      button: 0,
      clientX: 35,
      clientY: 20,
      pointerId: 12,
    });
    fireEvent.pointerUp(gizmo, { pointerId: 12 });

    expect(store.getState().values["view.orbit"]).toEqual(
      DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
    );
    expect(store.getState().history.undo).toHaveLength(0);
  });

  it("lets presses outside the circular gizmo bubble to canvas pan", async () => {
    const store = renderOrientationGizmoRuntime();
    const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo");
    mockOrientationGizmoBounds(gizmo);

    fireEvent.pointerDown(gizmo, {
      button: 0,
      clientX: 1,
      clientY: 1,
      pointerId: 13,
    });
    fireEvent.pointerMove(gizmo, {
      clientX: 11,
      clientY: 11,
      pointerId: 13,
    });
    fireEvent.pointerUp(gizmo, { pointerId: 13 });

    expect(store.getState().canvas.offset).toEqual({ x: 10, y: 10 });
    expect(store.getState().values["view.orbit"]).toEqual(
      DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
    );
  });

  it("ends gizmo drag ownership when pointer capture is lost", async () => {
    const store = renderOrientationGizmoRuntime();
    const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo");
    mockOrientationGizmoBounds(gizmo);

    fireEvent.pointerDown(gizmo, {
      button: 0,
      clientX: 59.5,
      clientY: 35,
      pointerId: 9,
    });
    fireEvent.lostPointerCapture(gizmo, { pointerId: 9 });
    fireEvent.pointerMove(gizmo, {
      clientX: 45,
      clientY: 45,
      pointerId: 9,
    });

    expect(store.getState().values["view.orbit"]).toEqual(
      DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
    );
  });
});
