import { describe, expect, it } from "vitest";
import {
  createEvent,
  defineToolcraft,
  fireEvent,
  renderControlsPanelWithSchema,
  screen,
  vi,
} from "../testing/controls-panel-test-utils";

describe("ControlsPanel vector pad interactions", () => {
  it("maps default spatial vector pad movement to screen coordinates", () => {
    const schema = defineToolcraft({
      canvas: { enabled: true },
      panels: {
        controls: {
          sections: [
            {
              controls: {
                position: {
                  defaultValue: { x: "0.00", y: "0.00" },
                  label: "Position",
                  target: "geometry.position",
                  type: "vector",
                },
              },
              title: "Geometry",
            },
          ],
          title: "Controls",
        },
      },
    });

    renderControlsPanelWithSchema(schema);
    const pad = screen.getByRole("button", { name: "Position X/Y pad" });

    expect(pad.getAttribute("data-vector-pad-coordinate-mode")).toBe("screen");
    vi.spyOn(pad, "getBoundingClientRect").mockReturnValue({
      bottom: 100,
      height: 100,
      left: 0,
      right: 100,
      toJSON: () => undefined,
      top: 0,
      width: 100,
      x: 0,
      y: 0,
    } as DOMRect);
    Object.defineProperty(pad, "setPointerCapture", {
      configurable: true,
      value: vi.fn(),
    });

    fireEvent.pointerDown(pad, {
      buttons: 1,
      clientX: 0,
      clientY: 0,
      pointerId: 1,
    });

    const values = JSON.parse(screen.getByTestId("values-json").textContent ?? "{}");
    expect(values["geometry.position"]).toEqual({ x: -1, y: -1 });
  });

  it("resets a vector pad to its default value on double click", () => {
    const schema = defineToolcraft({
      canvas: { enabled: true },
      panels: {
        controls: {
          sections: [
            {
              controls: {
                position: {
                  defaultValue: { x: "0.48", y: "-0.34" },
                  label: "Position",
                  target: "geometry.position",
                  type: "vector",
                },
              },
              title: "Geometry",
            },
          ],
          title: "Controls",
        },
      },
    });

    renderControlsPanelWithSchema(schema);
    const pad = screen.getByRole("button", { name: "Position X/Y pad" });

    vi.spyOn(pad, "getBoundingClientRect").mockReturnValue({
      bottom: 100,
      height: 100,
      left: 0,
      right: 100,
      toJSON: () => undefined,
      top: 0,
      width: 100,
      x: 0,
      y: 0,
    } as DOMRect);
    Object.defineProperty(pad, "setPointerCapture", {
      configurable: true,
      value: vi.fn(),
    });

    fireEvent.pointerDown(pad, {
      buttons: 1,
      clientX: 0,
      clientY: 0,
      pointerId: 1,
    });
    expect(
      JSON.parse(screen.getByTestId("values-json").textContent ?? "{}")[
        "geometry.position"
      ],
    ).toEqual({ x: -1, y: -1 });

    fireEvent.doubleClick(pad);

    const values = JSON.parse(screen.getByTestId("values-json").textContent ?? "{}");
    expect(values["geometry.position"]).toEqual({ x: 0.48, y: -0.34 });
    expect(screen.getByText("0.48, -0.34")).toBeTruthy();
  });

  it("locks vector pad movement to the dominant axis while shift is held", () => {
    const schema = defineToolcraft({
      canvas: { enabled: true },
      panels: {
        controls: {
          sections: [
            {
              controls: {
                position: {
                  defaultValue: { x: "0.00", y: "0.00" },
                  label: "Position",
                  target: "geometry.position",
                  type: "vector",
                },
              },
              title: "Geometry",
            },
          ],
          title: "Controls",
        },
      },
    });

    renderControlsPanelWithSchema(schema);
    const pad = screen.getByRole("button", { name: "Position X/Y pad" });

    vi.spyOn(pad, "getBoundingClientRect").mockReturnValue({
      bottom: 100,
      height: 100,
      left: 0,
      right: 100,
      toJSON: () => undefined,
      top: 0,
      width: 100,
      x: 0,
      y: 0,
    } as DOMRect);
    Object.defineProperty(pad, "setPointerCapture", {
      configurable: true,
      value: vi.fn(),
    });

    fireEvent.pointerDown(pad, {
      buttons: 1,
      clientX: 50,
      clientY: 50,
      pointerId: 1,
    });
    fireEvent.pointerMove(pad, {
      buttons: 1,
      clientX: 90,
      clientY: 70,
      pointerId: 1,
      shiftKey: true,
    });

    const values = JSON.parse(screen.getByTestId("values-json").textContent ?? "{}");
    expect(values["geometry.position"]).toEqual({ x: 0.8, y: 0 });
  });

  it("locks vector pad movement vertically when shift drag is y-dominant", () => {
    const schema = defineToolcraft({
      canvas: { enabled: true },
      panels: {
        controls: {
          sections: [
            {
              controls: {
                position: {
                  defaultValue: { x: "0.00", y: "0.00" },
                  label: "Position",
                  target: "geometry.position",
                  type: "vector",
                },
              },
              title: "Geometry",
            },
          ],
          title: "Controls",
        },
      },
    });

    renderControlsPanelWithSchema(schema);
    const pad = screen.getByRole("button", { name: "Position X/Y pad" });

    vi.spyOn(pad, "getBoundingClientRect").mockReturnValue({
      bottom: 100,
      height: 100,
      left: 0,
      right: 100,
      toJSON: () => undefined,
      top: 0,
      width: 100,
      x: 0,
      y: 0,
    } as DOMRect);
    Object.defineProperty(pad, "setPointerCapture", {
      configurable: true,
      value: vi.fn(),
    });

    fireEvent.pointerDown(pad, {
      buttons: 1,
      clientX: 50,
      clientY: 50,
      pointerId: 1,
    });
    fireEvent.pointerMove(pad, {
      buttons: 1,
      clientX: 70,
      clientY: 90,
      pointerId: 1,
      shiftKey: true,
    });

    const values = JSON.parse(screen.getByTestId("values-json").textContent ?? "{}");
    expect(values["geometry.position"]).toEqual({ x: 0, y: 0.8 });
  });

  it("renders vector pad values as compact rounded coordinates", () => {
    const schema = defineToolcraft({
      canvas: { enabled: true },
      panels: {
        controls: {
          sections: [
            {
              controls: {
                center: {
                  defaultValue: {
                    x: "-0.07070312499999998",
                    y: "-0.00392795138",
                  },
                  label: "Center",
                  target: "geometry.center",
                  type: "vector",
                },
              },
              title: "Geometry",
            },
          ],
          title: "Controls",
        },
      },
    });

    renderControlsPanelWithSchema(schema);

    expect(screen.getByText("-0.07, 0.00")).toBeTruthy();
    expect(screen.queryByText("-0.07070312499999998, -0.00392795138")).toBeNull();
  });

  it("prevents native text selection while dragging a vector pad", () => {
    const schema = defineToolcraft({
      canvas: { enabled: true },
      panels: {
        controls: {
          sections: [
            {
              controls: {
                center: {
                  defaultValue: { x: "0.00", y: "0.00" },
                  label: "Center",
                  target: "geometry.center",
                  type: "vector",
                },
              },
              title: "Geometry",
            },
          ],
          title: "Controls",
        },
      },
    });

    renderControlsPanelWithSchema(schema);
    const pad = screen.getByRole("button", { name: "Center X/Y pad" });

    vi.spyOn(pad, "getBoundingClientRect").mockReturnValue({
      bottom: 100,
      height: 100,
      left: 0,
      right: 100,
      toJSON: () => undefined,
      top: 0,
      width: 100,
      x: 0,
      y: 0,
    } as DOMRect);
    Object.defineProperty(pad, "setPointerCapture", {
      configurable: true,
      value: vi.fn(),
    });

    const pointerDown = createEvent.pointerDown(pad, {
      buttons: 1,
      clientX: 50,
      clientY: 50,
      pointerId: 1,
    });

    fireEvent(pad, pointerDown);

    expect(pointerDown.defaultPrevented).toBe(true);
    expect(pad.className).toContain("select-none");
  });

  it("allows cartesian vector pads when a product intentionally uses y-up math", () => {
    const schema = defineToolcraft({
      canvas: { enabled: true },
      panels: {
        controls: {
          sections: [
            {
              controls: {
                vector: {
                  coordinateMode: "cartesian",
                  defaultValue: { x: "0.00", y: "0.00" },
                  label: "Vector",
                  target: "math.vector",
                  type: "vector",
                },
              },
              title: "Math",
            },
          ],
          title: "Controls",
        },
      },
    });

    renderControlsPanelWithSchema(schema);
    const pad = screen.getByRole("button", { name: "Vector X/Y pad" });

    expect(pad.getAttribute("data-vector-pad-coordinate-mode")).toBe("cartesian");
    vi.spyOn(pad, "getBoundingClientRect").mockReturnValue({
      bottom: 100,
      height: 100,
      left: 0,
      right: 100,
      toJSON: () => undefined,
      top: 0,
      width: 100,
      x: 0,
      y: 0,
    } as DOMRect);
    Object.defineProperty(pad, "setPointerCapture", {
      configurable: true,
      value: vi.fn(),
    });

    fireEvent.pointerDown(pad, {
      buttons: 1,
      clientX: 0,
      clientY: 0,
      pointerId: 1,
    });

    const values = JSON.parse(screen.getByTestId("values-json").textContent ?? "{}");
    expect(values["math.vector"]).toEqual({ x: -1, y: 1 });
  });
});
