import { useState } from "react";
import { describe, it, expect, vi } from "vitest";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import {
  buildMultiAnglePrompt,
  DEFAULT_MULTI_ANGLE_SETTINGS,
  MULTI_ANGLE_PRESET_SETTINGS,
  MultiAngleEditor,
  type MultiAnglePresetId,
  type MultiAngleSettings,
} from "@/components/MultiAngleEditor";

vi.mock("@/i18n", () => {
  const messages: Record<string, string> = {
    "multiAngle.editorTitle": "Multi-Angle Editor",
    "multiAngle.sightControl": "Multi-angle sight control",
    "multiAngle.noImage": "No image",
    "multiAngle.horizontal": "Horizontal",
    "multiAngle.vertical": "Vertical",
    "multiAngle.zoom": "Zoom",
    "multiAngle.prompt": "Prompt",
    "multiAngle.enableCustomPrompt": "Enable custom prompt",
    "multiAngle.promptDialog": "Multi-angle prompt",
    "multiAngle.promptInput": "Multi-angle prompt input",
    "multiAngle.promptPlaceholder": "Optional prompt",
    "multiAngle.resetAria": "Reset multi-angle parameters",
    "multiAngle.reset": "Reset",
    "multiAngle.adjustVerticalUp": "Adjust vertical up",
    "multiAngle.adjustVerticalDown": "Adjust vertical down",
    "multiAngle.adjustHorizontalLeft": "Adjust horizontal left",
    "multiAngle.adjustHorizontalRight": "Adjust horizontal right",
    "multiAngle.preset.custom": "Custom",
    "multiAngle.preset.fisheye": "Fisheye",
    "multiAngle.preset.tilt": "Tilt",
    "multiAngle.preset.frontOverhead": "Front overhead",
    "multiAngle.preset.frontLow": "Front low angle",
    "multiAngle.preset.panoramicOverhead": "Panoramic overhead",
    "multiAngle.preset.back": "Back view",
  };

  return {
    useI18n: () => ({
      t: (key: string) => messages[key] ?? key,
    }),
  };
});

function MultiAngleHarness() {
  const [settings, setSettings] = useState<MultiAngleSettings>(DEFAULT_MULTI_ANGLE_SETTINGS);

  return (
    <MultiAngleEditor
      previewImage="data:image/png;base64,input"
      settings={settings}
      onChange={(patch) => setSettings((current) => ({ ...current, ...patch, preset: patch.preset ?? "custom" }))}
      onSelectPreset={(preset: MultiAnglePresetId) => setSettings({ ...MULTI_ANGLE_PRESET_SETTINGS[preset] })}
      onTogglePrompt={(enabled) => setSettings((current) => ({ ...current, includePrompt: enabled }))}
      onReset={() =>
        setSettings((current) => ({
          ...DEFAULT_MULTI_ANGLE_SETTINGS,
          includePrompt: current.includePrompt,
          promptText: current.promptText,
        }))
      }
    />
  );
}

describe("MultiAngleEditor", () => {
  it("renders default custom multi-angle controls", () => {
    render(<MultiAngleHarness />);

    expect(screen.getByText("Multi-Angle Editor")).toBeInTheDocument();
    expect(screen.getByRole("button", { name: "Custom" })).toBeEnabled();
    expect(screen.getByRole("button", { name: "Fisheye" })).toBeEnabled();
    expect(screen.getByRole("button", { name: "Tilt" })).toBeEnabled();
    expect(screen.getByLabelText("Horizontal")).toHaveValue("0");
    expect(screen.getByLabelText("Vertical")).toHaveValue("-30");
    expect(screen.getByLabelText("Zoom")).toHaveValue("5");
    expect(screen.getByRole("switch", { name: "Prompt" })).toHaveAttribute("aria-checked", "false");
    expect(screen.queryByRole("dialog", { name: "Multi-angle prompt" })).not.toBeInTheDocument();
  });

  it("applies the fisheye preset parameters and prompt", () => {
    render(<MultiAngleHarness />);

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

    expect(screen.getByRole("button", { name: "Fisheye" })).toHaveClass("border-[var(--border-strong)]");
    expect(screen.getByLabelText("Horizontal")).toHaveValue("0");
    expect(screen.getByLabelText("Vertical")).toHaveValue("30");
    expect(screen.getByLabelText("Zoom")).toHaveValue("10");
    expect(screen.getByRole("switch", { name: "Prompt" })).toHaveAttribute("aria-checked", "true");
    expect(screen.getByDisplayValue(/Ultra-close fisheye lens/)).toBeInTheDocument();
    expect(screen.getByDisplayValue(/barrel distortion/)).toBeInTheDocument();
  });

  it("syncs cube drag movement with custom parameters", async () => {
    render(<MultiAngleHarness />);

    const globe = screen.getByRole("application", { name: "Multi-angle sight control" });
    fireEvent.change(screen.getByLabelText("Vertical"), { target: { value: "0" } });

    fireEvent.pointerDown(globe, { pointerId: 1, pointerType: "mouse", clientX: 100, clientY: 100, buttons: 1 });
    fireEvent.pointerMove(globe, { pointerId: 1, pointerType: "mouse", clientX: 150, clientY: 80, buttons: 1 });

    await waitFor(() => expect(screen.getByLabelText("Horizontal")).toHaveValue("40"));
    expect(screen.getByLabelText("Vertical")).toHaveValue("-16");

    fireEvent.pointerUp(globe, { pointerId: 1, pointerType: "mouse" });

    fireEvent.change(screen.getByLabelText("Horizontal"), { target: { value: "360" } });
    fireEvent.change(screen.getByLabelText("Vertical"), { target: { value: "57" } });
    fireEvent.change(screen.getByLabelText("Zoom"), { target: { value: "8.6" } });

    expect(globe).toHaveAttribute("data-horizontal", "360");
    expect(globe).toHaveAttribute("data-vertical", "57");
    expect(globe).toHaveAttribute("data-zoom", "8.6");
  });

  it("wraps horizontal cube drag across zero degrees", async () => {
    render(<MultiAngleHarness />);

    const globe = screen.getByRole("application", { name: "Multi-angle sight control" });

    fireEvent.pointerDown(globe, { pointerId: 1, pointerType: "mouse", clientX: 100, clientY: 100, buttons: 1 });
    fireEvent.pointerMove(globe, { pointerId: 1, pointerType: "mouse", clientX: 80, clientY: 100, buttons: 1 });

    await waitFor(() => expect(screen.getByLabelText("Horizontal")).toHaveValue("344"));
  });

  it("builds a platform-neutral multi-angle prompt", () => {
    const prompt = buildMultiAnglePrompt({
      ...DEFAULT_MULTI_ANGLE_SETTINGS,
      horizontal: 316,
      vertical: 57,
      zoom: 8.6,
      includePrompt: true,
      promptText: "Keep background layers clear",
    });

    expect(prompt).toMatch(/horizontal orbit 316 degrees counterclockwise/);
    expect(prompt).toMatch(/front overhead view/);
    expect(prompt).toMatch(/shot scale zoom 8.6/);
    expect(prompt).toMatch(/normal 2D image/);
    expect(prompt).toMatch(/Do not create a 3D model/);
    expect(prompt).toMatch(/prompt: Keep background layers clear/);
    expect(prompt).not.toMatch(/libTV/i);
  });
});
