/**
 * Мышь-ввод камеры игры (трек «Режимы камеры»): поворот зажатой ЛКМ —
 * drag по канвасу (setPointerCapture держит кнопку даже за пределами),
 * колесо — дистанция орбиты (только third person). enabled гасится в
 * меню/сумке/катсцене — ставит tick() в main.ts. Конфликтов на канвасе
 * нет: слушатели клавиш висят на window, канвас раньше получал только их.
 */
import type { VoxelRenderer } from '@rpg/engine';

export class CameraInput {
    private dragging = false;
    private px = 0;
    private py = 0;
    private readonly off: Array<() => void> = [];

    /** true — ввод активен (меню/сумка/катсцена гасят). */
    enabled = true;

    constructor(private readonly canvas: HTMLCanvasElement, private readonly renderer: VoxelRenderer) {
        const add = (
            t: EventTarget, type: string, f: EventListener, opts?: AddEventListenerOptions,
        ): void => {
            t.addEventListener(type, f, opts);
            this.off.push(() => t.removeEventListener(type, f, opts));
        };
        add(this.canvas, 'pointerdown', (e) => {
            const ev = e as PointerEvent;
            if (!this.enabled || ev.button !== 0) return;
            this.dragging = true;
            this.px = ev.clientX;
            this.py = ev.clientY;
            this.canvas.setPointerCapture(ev.pointerId);
        });
        add(this.canvas, 'pointermove', (e) => {
            if (!this.dragging) return;
            const ev = e as PointerEvent;
            const dx = ev.clientX - this.px, dy = ev.clientY - this.py;
            this.px = ev.clientX;
            this.py = ev.clientY;
            const o = this.renderer.orbitState();
            // скорость как у орбиты ModelViewer: ~0.005 рад/пиксель
            this.renderer.setOrbit({ yaw: o.yaw - dx * 0.005, pitch: o.pitch + dy * 0.005 });
        });
        const end = (): void => { this.dragging = false; };
        add(this.canvas, 'pointerup', end);
        add(this.canvas, 'pointercancel', end);
        add(this.canvas, 'wheel', (e) => {
            const ev = e as WheelEvent;
            if (!this.enabled || this.renderer.cameraMode() !== 'third') return;
            ev.preventDefault(); // страница не скроллится под зумом
            const o = this.renderer.orbitState();
            this.renderer.setOrbit({ dist: o.dist * (ev.deltaY > 0 ? 1.1 : 0.9) });
        }, { passive: false });
    }

    /** Снять слушатели (страничный рендер демки живёт вечно — для полноты). */
    dispose(): void {
        for (const f of this.off) f();
        this.off.length = 0;
    }
}