/**
 * Input Classifier
 *
 * Classifies pointer events into input sources (finger, pencil, mouse)
 * and extracts stylus-specific data (pressure, tilt).
 *
 * This is the foundation of the touch-first input architecture:
 * - Pencil draws/selects
 * - Fingers navigate (pan/zoom)
 * - Mouse does both
 */

// =============================================================================
// Types
// =============================================================================

/** Input device type */
export type InputSource = 'finger' | 'pencil' | 'mouse';

/** Classified pointer with source-specific metadata */
export interface ClassifiedPointer {
    /** Detected input source */
    source: InputSource;
    /** Unique pointer ID from the PointerEvent */
    pointerId: number;
    /** Pressure (0–1). 0.5 for mouse, actual pressure for pencil/finger */
    pressure: number;
    /** Tilt angle in X (-90 to 90). 0 for non-stylus. */
    tiltX: number;
    /** Tilt angle in Y (-90 to 90). 0 for non-stylus. */
    tiltY: number;
    /** Whether this is the primary pointer */
    isPrimary: boolean;
    /** Original pointer type string from the event */
    rawPointerType: string;
}

/** Capabilities detected for the current device */
export interface InputCapabilities {
    /** Device supports touch input */
    hasTouch: boolean;
    /** Device has a stylus/pen (detected on first pen event) */
    hasStylus: boolean;
    /** Device has a mouse (or mouse-like pointer) */
    hasMouse: boolean;
    /** Device has coarse pointer (finger) */
    hasCoarsePointer: boolean;
}

// =============================================================================
// Classification
// =============================================================================

/**
 * Classify a PointerEvent into an InputSource with metadata.
 *
 * Uses `PointerEvent.pointerType` as the primary signal:
 * - 'pen' → pencil (Apple Pencil, Surface Pen, Wacom, etc.)
 * - 'touch' → finger
 * - 'mouse' → mouse
 *
 * Falls back to 'mouse' for unknown pointer types.
 */
export function classifyPointer(e: PointerEvent): ClassifiedPointer {
    const source = pointerTypeToSource(e.pointerType);

    return {
        source,
        pointerId: e.pointerId,
        pressure: e.pressure,
        tiltX: e.tiltX,
        tiltY: e.tiltY,
        isPrimary: e.isPrimary,
        rawPointerType: e.pointerType,
    };
}

/**
 * Map PointerEvent.pointerType string to InputSource.
 */
function pointerTypeToSource(pointerType: string): InputSource {
    switch (pointerType) {
        case 'pen':
            return 'pencil';
        case 'touch':
            return 'finger';
        case 'mouse':
            return 'mouse';
        default:
            // Unknown pointer types (e.g. future devices) default to mouse behavior
            return 'mouse';
    }
}

// =============================================================================
// Device Capability Detection
// =============================================================================

/**
 * Detect input capabilities of the current device.
 *
 * Uses media queries and navigator APIs for initial detection.
 * Note: `hasStylus` starts as false and is set to true on first pen event
 * (there's no reliable way to detect stylus support without an event).
 */
export function detectInputCapabilities(): InputCapabilities {
    if (typeof window === 'undefined') {
        // SSR: assume desktop defaults
        return {
            hasTouch: false,
            hasStylus: false,
            hasMouse: true,
            hasCoarsePointer: false,
        };
    }

    const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;

    // matchMedia for pointer capabilities
    const supportsMatchMedia = typeof window.matchMedia === 'function';
    const hasCoarsePointer = supportsMatchMedia ? window.matchMedia('(pointer: coarse)').matches : false;
    const hasFinePointer = supportsMatchMedia ? window.matchMedia('(pointer: fine)').matches : true;

    // Heuristic: if we have both coarse and fine, likely a tablet with stylus support
    // But we won't confirm stylus until we see a pen event
    const hasMouse = hasFinePointer || !hasTouch;

    return {
        hasTouch,
        hasStylus: false, // Set to true on first pen event
        hasMouse,
        hasCoarsePointer,
    };
}

// =============================================================================
// Gesture Threshold Helpers
// =============================================================================

/** Threshold values per input source */
export interface GestureThresholds {
    /** Minimum movement to start a drag (px) */
    dragThreshold: number;
    /** Tap detection radius (px) */
    tapThreshold: number;
    /** Long-press duration (ms) */
    longPressDuration: number;
    /** Movement limit during long-press before cancellation (px) */
    longPressMoveLimit: number;
}

/**
 * Get gesture thresholds appropriate for the given input source.
 *
 * Fingers need larger thresholds (imprecise, large contact area).
 * Stylus is the most precise.
 * Mouse is in between.
 */
export function getGestureThresholds(source: InputSource): GestureThresholds {
    switch (source) {
        case 'finger':
            return {
                dragThreshold: 10,
                tapThreshold: 10,
                longPressDuration: 600,
                longPressMoveLimit: 10,
            };
        case 'pencil':
            return {
                dragThreshold: 2,
                tapThreshold: 3,
                longPressDuration: 500,
                longPressMoveLimit: 5,
            };
        case 'mouse':
            return {
                dragThreshold: 3,
                tapThreshold: 5,
                longPressDuration: 0, // Mouse uses right-click instead
                longPressMoveLimit: 0,
            };
    }
}

// =============================================================================
// Hit Target Helpers
// =============================================================================

/** Minimum interactive target sizes per Apple HIG / Material Design */
export const HIT_TARGET_SIZES = {
    /** Minimum touch target (Apple HIG: 44pt) */
    finger: 44,
    /** Stylus target (precise, can use smaller targets) */
    pencil: 24,
    /** Mouse target (hover-discoverable, smallest) */
    mouse: 16,
} as const;

/**
 * Get the appropriate hit target size for the current input source.
 * Used to size invisible padding around small visual elements
 * (resize handles, ports, edge connection handles).
 */
export function getHitTargetSize(source: InputSource): number {
    return HIT_TARGET_SIZES[source];
}
