/**
 * Input Store
 *
 * Jotai atoms tracking active pointers, input sources, and device capabilities.
 * Components read these atoms to adapt behavior per input source.
 *
 * Key derived atoms:
 * - `primaryInputSourceAtom` — the last-used input source ('finger' | 'pencil' | 'mouse')
 * - `isStylusActiveAtom` — true when a pen pointer is currently down
 * - `isMultiTouchAtom` — true when 2+ fingers are touching
 */

import { atom } from 'jotai';
import type { InputSource, ClassifiedPointer, InputCapabilities } from './input-classifier';
import { detectInputCapabilities } from './input-classifier';

// =============================================================================
// Core Atoms
// =============================================================================

/**
 * Map of all currently active (down) pointers.
 * Updated on pointer down/up/cancel events.
 */
export const activePointersAtom = atom<Map<number, ClassifiedPointer>>(new Map());

/**
 * The primary/last-used input source.
 * Updated whenever a pointer goes down — the most recent source wins.
 * Defaults to 'mouse' on desktop, 'finger' on mobile.
 */
export const primaryInputSourceAtom = atom<InputSource>('mouse');

/**
 * Device input capabilities.
 * Initialized once on mount, updated when stylus is first detected.
 */
export const inputCapabilitiesAtom = atom<InputCapabilities>(detectInputCapabilities());

// =============================================================================
// Derived Atoms
// =============================================================================

/**
 * Whether a stylus/pen is currently touching the screen.
 * When true, finger touches should be routed to pan/zoom only (palm rejection).
 */
export const isStylusActiveAtom = atom((get) => {
    const pointers = get(activePointersAtom);
    for (const [, pointer] of pointers) {
        if (pointer.source === 'pencil') return true;
    }
    return false;
});

/**
 * Whether multiple fingers are currently touching.
 * When true, the gesture is likely a pinch or two-finger pan.
 */
export const isMultiTouchAtom = atom((get) => {
    const pointers = get(activePointersAtom);
    let fingerCount = 0;
    for (const [, pointer] of pointers) {
        if (pointer.source === 'finger') fingerCount++;
    }
    return fingerCount > 1;
});

/**
 * Count of active finger pointers.
 */
export const fingerCountAtom = atom((get) => {
    const pointers = get(activePointersAtom);
    let count = 0;
    for (const [, pointer] of pointers) {
        if (pointer.source === 'finger') count++;
    }
    return count;
});

/**
 * Whether the device primarily uses touch (tablet/phone).
 * Used for showing/hiding touch-specific UI (e.g., ViewportControls).
 */
export const isTouchDeviceAtom = atom((get) => {
    const caps = get(inputCapabilitiesAtom);
    return caps.hasTouch;
});

// =============================================================================
// Action Atoms
// =============================================================================

/**
 * Register a pointer down event.
 * Updates active pointers and primary input source.
 */
export const pointerDownAtom = atom(
    null,
    (get, set, pointer: ClassifiedPointer) => {
        const pointers = new Map(get(activePointersAtom));
        pointers.set(pointer.pointerId, pointer);
        set(activePointersAtom, pointers);
        set(primaryInputSourceAtom, pointer.source);

        // Auto-detect stylus capability on first pen event
        if (pointer.source === 'pencil') {
            const caps = get(inputCapabilitiesAtom);
            if (!caps.hasStylus) {
                set(inputCapabilitiesAtom, { ...caps, hasStylus: true });
            }
        }
    },
);

/**
 * Unregister a pointer up/cancel event.
 */
export const pointerUpAtom = atom(
    null,
    (get, set, pointerId: number) => {
        const pointers = new Map(get(activePointersAtom));
        pointers.delete(pointerId);
        set(activePointersAtom, pointers);
    },
);

/**
 * Clear all active pointers.
 * Call on blur or visibility change to prevent stuck pointers.
 */
export const clearPointersAtom = atom(
    null,
    (_get, set) => {
        set(activePointersAtom, new Map());
    },
);
