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

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

describe("Toolcraft direct model orbit integration", () => {
  it("ends direct orbit ownership when pointer capture is lost", () => {
    vi.useFakeTimers();
    const store = renderOrientationGizmoRuntime();
    const surface = screen.getByTestId("model-surface");
    mockModelSurfaceBounds(surface);

    fireEvent.pointerDown(surface, {
      button: 0,
      clientX: 100,
      clientY: 100,
      pointerId: 10,
    });
    fireEvent.lostPointerCapture(surface, { pointerId: 10 });
    fireEvent.pointerMove(surface, {
      clientX: 130,
      clientY: 120,
      pointerId: 10,
    });
    act(() => {
      vi.advanceTimersByTime(20);
    });

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

  it("orbits on a model hit and leaves canvas pan untouched", () => {
    vi.useFakeTimers();
    const store = renderOrientationGizmoRuntime();
    const surface = screen.getByTestId("model-surface");
    mockModelSurfaceBounds(surface);

    fireEvent.pointerDown(surface, {
      button: 0,
      clientX: 100,
      clientY: 100,
      pointerId: 2,
    });
    fireEvent.pointerMove(surface, {
      clientX: 130,
      clientY: 112,
      pointerId: 2,
    });
    act(() => {
      vi.advanceTimersByTime(20);
    });
    fireEvent.pointerUp(surface, { pointerId: 2 });

    expect(store.getState().canvas.offset).toEqual({ x: 0, y: 0 });
    expectOrientationPoseClose(
      readToolcraftOrientationPose(store.getState().values["view.orbit"]),
      getToolcraftOrientationPoseFromPointerDelta(
        DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
        30,
        12,
      ),
    );
    act(() => {
      store.dispatch({ type: "history.undo" });
    });
    expect(store.getState().values["view.orbit"]).toEqual(
      DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
    );
  });

  it("passes a model miss to canvas pan", () => {
    const store = renderOrientationGizmoRuntime({ hit: false });
    const surface = screen.getByTestId("model-surface");

    fireEvent.pointerDown(surface, {
      button: 0,
      clientX: 10,
      clientY: 20,
      pointerId: 3,
    });
    fireEvent.pointerMove(surface, {
      clientX: 30,
      clientY: 45,
      pointerId: 3,
    });
    fireEvent.pointerUp(surface, { pointerId: 3 });

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

  it("passes a modified primary press to canvas pan even on a model hit", () => {
    const store = renderOrientationGizmoRuntime({ hit: true });
    const surface = screen.getByTestId("model-surface");

    fireEvent.pointerDown(surface, {
      button: 0,
      clientX: 10,
      clientY: 20,
      pointerId: 4,
      shiftKey: true,
    });
    fireEvent.pointerMove(surface, {
      clientX: 25,
      clientY: 30,
      pointerId: 4,
      shiftKey: true,
    });
    fireEvent.pointerUp(surface, { pointerId: 4, shiftKey: true });

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