class VirtualKeyboard {
  constructor(onSendText, onSendKey) {
    this.onSendText = onSendText;
    this.onSendKey = onSendKey;
    this.ctrlActive = false;
    this.ctrlLocked = false;
    this.altActive = false;
    this.altLocked = false;
    this.shiftActive = false;
    this.shiftLocked = false;
    this._repeatTimer = null;
    this._repeatInterval = null;
    this._composingEnterPending = false;

    this.textInput = document.getElementById('text-input');
    this.sendBtn = document.getElementById('send-btn');
    this.ctrlKey = document.getElementById('ctrl-key');
    this.altKey = document.getElementById('alt-key');
    this.shiftKey = document.getElementById('shift-key');

    this.init();
  }

  static get REPEAT_KEYS() {
    return new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'PageUp', 'PageDown']);
  }

  static get REPEAT_INITIAL_DELAY() { return 400; }
  static get REPEAT_INTERVAL() { return 80; }

  init() {
    // Text input + send
    this.sendBtn.addEventListener('click', () => this.submitText());
    this.textInput.addEventListener('compositionend', () => {
      if (this._composingEnterPending) {
        this._composingEnterPending = false;
        setTimeout(() => this.submitText(), 0);
      }
    });
    this.textInput.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') {
        if (e.isComposing || e.keyCode === 229) {
          this._composingEnterPending = true;
          return;
        }
        e.preventDefault();
        this.submitText();
      }
    });

    // Ctrl modifier
    this.ctrlKey.addEventListener('click', () => this.toggleModifier('ctrl'));
    this.ctrlKey.addEventListener('dblclick', () => this.lockModifier('ctrl'));

    // Alt modifier
    this.altKey.addEventListener('click', () => this.toggleModifier('alt'));
    this.altKey.addEventListener('dblclick', () => this.lockModifier('alt'));

    // Shift modifier
    this.shiftKey.addEventListener('click', () => this.toggleModifier('shift'));
    this.shiftKey.addEventListener('dblclick', () => this.lockModifier('shift'));

    // Special keys
    document.querySelectorAll('.key[data-key]').forEach((btn) => {
      if (btn.classList.contains('modifier')) return;
      const key = btn.dataset.key;
      if (VirtualKeyboard.REPEAT_KEYS.has(key)) {
        const startRepeat = () => {
          this._clearRepeat();
          this.handleKeyPress(key);
          this._repeatTimer = setTimeout(() => {
            this._repeatInterval = setInterval(() => {
              this.handleKeyPress(key);
            }, VirtualKeyboard.REPEAT_INTERVAL);
          }, VirtualKeyboard.REPEAT_INITIAL_DELAY);
        };
        btn.addEventListener('mousedown', startRepeat);
        btn.addEventListener('touchstart', startRepeat, { passive: true });
        btn.addEventListener('mouseup', () => this._clearRepeat());
        btn.addEventListener('mouseleave', () => this._clearRepeat());
        btn.addEventListener('touchend', () => this._clearRepeat());
        btn.addEventListener('touchcancel', () => this._clearRepeat());
      } else {
        btn.addEventListener('click', () => this.handleKeyPress(key));
      }
    });
  }

  _haptic() {
    if (navigator.vibrate) navigator.vibrate(8);
  }

  _clearRepeat() {
    clearTimeout(this._repeatTimer);
    clearInterval(this._repeatInterval);
    this._repeatTimer = null;
    this._repeatInterval = null;
  }

  submitText() {
    this._haptic();
    const text = this.textInput.value;
    if (text) {
      this.onSendText(text + '\n');
      this.textInput.value = '';
    } else {
      // Empty submit = Enter key
      this.onSendKey('Enter');
    }
    this.textInput.focus();
  }

  handleKeyPress(key) {
    this._haptic();
    // Check for pre-built shortcut keys like Ctrl-c
    if (key.startsWith('Ctrl-') || key.startsWith('Alt-') || key.startsWith('Shift-')) {
      this.onSendKey(key);
      return;
    }

    // Apply active modifiers
    let finalKey = key;
    if (this.shiftActive) {
      finalKey = `Shift-${finalKey}`;
      if (!this.shiftLocked) this.deactivateModifier('shift');
    }
    if (this.ctrlActive) {
      finalKey = `Ctrl-${finalKey}`;
      if (!this.ctrlLocked) this.deactivateModifier('ctrl');
    }
    if (this.altActive) {
      finalKey = `Alt-${finalKey}`;
      if (!this.altLocked) this.deactivateModifier('alt');
    }

    this.onSendKey(finalKey);
  }

  toggleModifier(mod) {
    this._haptic();
    if (mod === 'ctrl') {
      if (this.ctrlLocked) { this.deactivateModifier('ctrl'); return; }
      this.ctrlActive = !this.ctrlActive;
      this.ctrlKey.classList.toggle('active', this.ctrlActive);
    } else if (mod === 'alt') {
      if (this.altLocked) { this.deactivateModifier('alt'); return; }
      this.altActive = !this.altActive;
      this.altKey.classList.toggle('active', this.altActive);
    } else if (mod === 'shift') {
      if (this.shiftLocked) { this.deactivateModifier('shift'); return; }
      this.shiftActive = !this.shiftActive;
      this.shiftKey.classList.toggle('active', this.shiftActive);
    }
  }

  lockModifier(mod) {
    if (mod === 'ctrl') {
      this.ctrlActive = true;
      this.ctrlLocked = true;
      this.ctrlKey.classList.add('active', 'locked');
    } else if (mod === 'alt') {
      this.altActive = true;
      this.altLocked = true;
      this.altKey.classList.add('active', 'locked');
    } else if (mod === 'shift') {
      this.shiftActive = true;
      this.shiftLocked = true;
      this.shiftKey.classList.add('active', 'locked');
    }
  }

  deactivateModifier(mod) {
    if (mod === 'ctrl') {
      this.ctrlActive = false;
      this.ctrlLocked = false;
      this.ctrlKey.classList.remove('active', 'locked');
    } else if (mod === 'alt') {
      this.altActive = false;
      this.altLocked = false;
      this.altKey.classList.remove('active', 'locked');
    } else if (mod === 'shift') {
      this.shiftActive = false;
      this.shiftLocked = false;
      this.shiftKey.classList.remove('active', 'locked');
    }
  }

  focus() {
    this.textInput.focus();
  }
}

window.VirtualKeyboard = VirtualKeyboard;
