/**
 * Input element key handler — manages text editing operations for <input>.
 *
 * Given a key event and the current input state (value + cursor position),
 * produces the next state. The screen wires this into the key dispatch loop
 * for any focused <input> node.
 */

/**
 * Process a key event against input state, returning the next state.
 * Pure function — no side effects.
 */
export function handleInputKey(key, state, options) {
  const multiline = options?.multiline ?? false;
  const {
    value,
    cursorPos
  } = state;
  const result = {
    value,
    cursorPos,
    changed: false,
    submit: false
  };

  // Modifier-only keys (shift, ctrl, etc.) — ignore
  if (key.name === "leftshift" || key.name === "rightshift" || key.name === "leftctrl" || key.name === "rightctrl" || key.name === "leftalt" || key.name === "rightalt" || key.name === "leftsuper" || key.name === "rightsuper" || key.name === "capslock" || key.name === "numlock") {
    return result;
  }

  // Release events — ignore
  if (key.eventType === "release") return result;

  // Navigation
  if (key.name === "left") {
    result.cursorPos = Math.max(0, cursorPos - 1);
    return result;
  }
  if (key.name === "right") {
    result.cursorPos = Math.min(value.length, cursorPos + 1);
    return result;
  }
  if (key.name === "home" || key.ctrl && key.name === "a") {
    // Move to start of current line
    const lineStart = value.lastIndexOf("\n", cursorPos - 1) + 1;
    result.cursorPos = lineStart;
    return result;
  }
  if (key.name === "end" || key.ctrl && key.name === "e") {
    // Move to end of current line
    const lineEnd = value.indexOf("\n", cursorPos);
    result.cursorPos = lineEnd === -1 ? value.length : lineEnd;
    return result;
  }
  if (key.name === "up") {
    result.cursorPos = moveCursorVertically(value, cursorPos, -1);
    return result;
  }
  if (key.name === "down") {
    result.cursorPos = moveCursorVertically(value, cursorPos, 1);
    return result;
  }

  // Deletion
  if (key.name === "backspace") {
    if (cursorPos > 0) {
      result.value = value.slice(0, cursorPos - 1) + value.slice(cursorPos);
      result.cursorPos = cursorPos - 1;
      result.changed = true;
    }
    return result;
  }
  if (key.name === "delete") {
    if (cursorPos < value.length) {
      result.value = value.slice(0, cursorPos) + value.slice(cursorPos + 1);
      result.changed = true;
    }
    return result;
  }

  // Kill line (ctrl+k) — delete from cursor to end of line
  if (key.ctrl && key.name === "k") {
    const lineEnd = value.indexOf("\n", cursorPos);
    const end = lineEnd === -1 ? value.length : lineEnd;
    if (cursorPos < end) {
      result.value = value.slice(0, cursorPos) + value.slice(end);
      result.changed = true;
    }
    return result;
  }

  // Kill word backward (ctrl+w / ctrl+backspace)
  if (key.ctrl && (key.name === "w" || key.name === "backspace")) {
    if (cursorPos > 0) {
      const before = value.slice(0, cursorPos);
      const trimmed = before.replace(/\S+\s*$|^\s+$/, "");
      result.value = trimmed + value.slice(cursorPos);
      result.cursorPos = trimmed.length;
      result.changed = true;
    }
    return result;
  }

  // Submit / newline — behavior depends on multiline prop
  if (key.name === "return" || key.name === "linefeed") {
    if (multiline) {
      // Multiline: Enter inserts newline, Ctrl+Enter submits
      if (key.ctrl || key.meta) {
        result.submit = true;
        return result;
      }
      result.value = `${value.slice(0, cursorPos)}\n${value.slice(cursorPos)}`;
      result.cursorPos = cursorPos + 1;
      result.changed = true;
      return result;
    }
    // Single-line: Enter submits
    result.submit = true;
    return result;
  }

  // Tab — insert tab (or could be handled by focus system later)
  if (key.name === "tab" && !key.shift) {
    result.value = `${value.slice(0, cursorPos)}\t${value.slice(cursorPos)}`;
    result.cursorPos = cursorPos + 1;
    result.changed = true;
    return result;
  }

  // Ignore other control sequences
  if (key.ctrl || key.meta) return result;

  // Printable character insertion
  if (key.sequence && key.sequence.length > 0 && !key.ctrl && !key.meta) {
    const char = key.sequence;
    // Filter out non-printable sequences (escape, function keys, etc.)
    if (key.name === "escape" || key.name === "tab" || key.name === "space" || key.name.startsWith("f") && key.name.length <= 3 && /^f\d+$/.test(key.name)) {
      if (key.name === "space") {
        result.value = `${value.slice(0, cursorPos)} ${value.slice(cursorPos)}`;
        result.cursorPos = cursorPos + 1;
        result.changed = true;
      }
      return result;
    }
    result.value = value.slice(0, cursorPos) + char + value.slice(cursorPos);
    result.cursorPos = cursorPos + char.length;
    result.changed = true;
    return result;
  }
  return result;
}

/**
 * Move cursor up or down by `delta` lines within a multi-line string.
 * Tries to maintain the column position.
 */
function moveCursorVertically(value, cursorPos, delta) {
  const lines = value.split("\n");

  // Find which line and column the cursor is on
  let charCount = 0;
  let currentLine = 0;
  let currentCol = 0;
  for (let i = 0; i < lines.length; i++) {
    const lineLen = (lines[i] ?? "").length;
    if (cursorPos <= charCount + lineLen) {
      currentLine = i;
      currentCol = cursorPos - charCount;
      break;
    }
    charCount += lineLen + 1; // +1 for \n
  }
  const targetLine = Math.max(0, Math.min(lines.length - 1, currentLine + delta));
  if (targetLine === currentLine) return cursorPos;

  // Calculate new cursor position maintaining column
  const targetLineLen = (lines[targetLine] ?? "").length;
  const targetCol = Math.min(currentCol, targetLineLen);
  let newPos = 0;
  for (let i = 0; i < targetLine; i++) {
    newPos += (lines[i] ?? "").length + 1;
  }
  return newPos + targetCol;
}
//# sourceMappingURL=input-handler.jsx.map
