/**
 * Numpad Component - Alpine.js component for touch-friendly numeric input
 * Used for measurement data entry in task_execute.html
 */

function numpad() {
  return {
    // State
    value: '',           // String representation of the current value
    negative: false,     // Whether the value is negative
    hasDecimal: false,   // Whether a decimal point has been entered
    unit: 'mm',          // Unit of measurement (can be set externally)
    maxIntDigits: 6,     // Maximum integer digits
    maxDecDigits: 6,     // Maximum decimal digits

    // HID burst detection (USB caliper vs manual typing)
    _lastKeyTime: 0,     // Timestamp of last keystroke
    _burstCount: 0,      // Consecutive fast keystrokes

    /**
     * Get the display value with sign
     */
    get displayValue() {
      if (!this.value) return '';
      return (this.negative ? '-' : '') + this.value;
    },

    /**
     * Get the numeric value as a number
     */
    get numericValue() {
      if (!this.value) return null;
      const v = parseFloat(this.value);
      return this.negative ? -v : v;
    },

    /**
     * Check if a valid value has been entered
     */
    get hasValue() {
      return this.value.length > 0 && this.value !== '.';
    },

    /**
     * Add a digit to the current value
     * @param {string} d - The digit to add (0-9)
     */
    addDigit(d) {
      // Validate: don't exceed max digits
      const parts = this.value.split('.');

      if (this.hasDecimal) {
        // Check decimal part length
        if (parts[1] && parts[1].length >= this.maxDecDigits) return;
      } else {
        // Check integer part length
        if (parts[0] && parts[0].length >= this.maxIntDigits) return;
      }

      // Prevent leading zeros (except "0.")
      if (this.value === '0' && d !== '.') {
        this.value = d;
        return;
      }

      this.value += d;
    },

    /**
     * Add a decimal point to the current value
     */
    addDecimal() {
      // Don't add decimal if one already exists
      if (this.hasDecimal) return;

      // If value is empty, start with "0."
      if (!this.value) this.value = '0';

      this.value += '.';
      this.hasDecimal = true;
    },

    /**
     * Toggle the sign of the current value
     */
    toggleSign() {
      if (!this.value) return;
      this.negative = !this.negative;
    },

    /**
     * Remove the last character from the current value
     */
    backspace() {
      if (!this.value) return;

      const removed = this.value.charAt(this.value.length - 1);

      // If removing decimal point, update flag
      if (removed === '.') this.hasDecimal = false;

      this.value = this.value.slice(0, -1);
    },

    /**
     * Clear all entered data
     */
    clearAll() {
      this.value = '';
      this.negative = false;
      this.hasDecimal = false;
    },

    /**
     * Confirm the current value and dispatch event
     */
    confirm() {
      if (!this.hasValue) return;

      const val = this.numericValue;

      // Determine input method: 3+ fast keystrokes = USB caliper burst
      const inputMethod = this._burstCount >= 3 ? 'usb_caliper' : 'manual';

      // Dispatch custom event for parent component to handle
      this.$dispatch('numpad-confirm', { value: val, inputMethod: inputMethod });

      // Reset after confirmation
      this.clearAll();
      this._burstCount = 0;
      this._lastKeyTime = 0;
    },

    /**
     * Set a value programmatically (e.g., from USB caliper)
     * @param {number} val - The numeric value to set
     */
    setValue(val) {
      this.clearAll();

      // Handle negative values
      if (val < 0) {
        this.negative = true;
        val = Math.abs(val);
      }

      this.value = val.toString();

      // Update decimal flag if value contains decimal point
      if (this.value.includes('.')) this.hasDecimal = true;
    },

    /**
     * Set the unit of measurement
     * @param {string} newUnit - The unit to set (e.g., 'mm', 'cm', 'in')
     */
    setUnit(newUnit) {
      this.unit = newUnit;
    },

    /**
     * Handle keyboard input for physical keyboard support
     * @param {KeyboardEvent} e - The keyboard event
     */
    handleKeydown(e) {
      // Ignore keystrokes aimed at an editable field (e.g. the supervisor
      // login modal). The numpad has no text inputs of its own, so this
      // window-level capture is only meant for the USB caliper / keyboard
      // wedge when no field is focused. Without this guard the numpad would
      // swallow digits and Backspace inside those inputs.
      const t = e.target;
      if (t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' ||
                t.tagName === 'SELECT' || t.isContentEditable)) {
        return;
      }

      // Number keys
      if (e.key >= '0' && e.key <= '9') {
        e.preventDefault();
        this._trackBurst();
        this.addDigit(e.key);
      }
      // Decimal point (both . and ,)
      else if (e.key === '.' || e.key === ',') {
        e.preventDefault();
        this._trackBurst();
        this.addDecimal();
      }
      // Backspace
      else if (e.key === 'Backspace') {
        e.preventDefault();
        this.backspace();
      }
      // Escape - clear all
      else if (e.key === 'Escape') {
        e.preventDefault();
        this.clearAll();
      }
      // Enter - confirm
      else if (e.key === 'Enter') {
        e.preventDefault();
        this.confirm();
      }
      // Minus sign - toggle sign
      else if (e.key === '-') {
        e.preventDefault();
        this.toggleSign();
      }
    },

    /**
     * Track keystroke timing for HID burst detection.
     * USB calipers send digits in rapid succession (<80ms apart).
     * Human typing is much slower (>100ms between keys).
     */
    _trackBurst() {
      const now = performance.now();
      const gap = now - this._lastKeyTime;

      if (this._lastKeyTime > 0 && gap < 80) {
        this._burstCount++;
      } else {
        this._burstCount = 1;
      }

      this._lastKeyTime = now;
    }
  };
}
