/** Cursor-aware token helpers for ChatInput (@ mentions, / commands, ! bash). */

export interface EditorToken {
  /** Inclusive start index in full text */
  start: number;
  /** Exclusive end index */
  end: number;
  /** Raw token text (includes leading @ or /) */
  raw: string;
}

/**
 * Word under / immediately before the cursor, split on whitespace.
 * Used for `/` slash and `@` file mention autocomplete.
 */
export function getTokenAtCursor(text: string, cursor: number): EditorToken {
  const safeCursor = Math.max(0, Math.min(cursor, text.length));
  const before = text.slice(0, safeCursor);
  const lastSpace = Math.max(before.lastIndexOf(" "), before.lastIndexOf("\n"), before.lastIndexOf("\t"));
  const start = lastSpace === -1 ? 0 : lastSpace + 1;
  const raw = before.slice(start);
  return { start, end: safeCursor, raw };
}

export interface BashLineParse {
  /** true when line starts with !! (exclude output from LLM context) */
  excludeFromContext: boolean;
  /** Shell command body after ! or !! */
  command: string;
}

/**
 * Parse a full message as a local bash line (pi TUI `!` / `!!` mode).
 * Only matches when the trimmed message starts with `!`.
 * Mid-message exclamation marks are not treated as bash.
 */
export function parseBashLine(text: string): BashLineParse | null {
  const trimmed = text.trim();
  if (!trimmed.startsWith("!")) return null;

  // !!command — exclude from context
  if (trimmed.startsWith("!!")) {
    const command = trimmed.slice(2).trimStart();
    if (!command) return null;
    return { excludeFromContext: true, command };
  }

  // !command — include in context
  const command = trimmed.slice(1).trimStart();
  if (!command) return null;
  return { excludeFromContext: false, command };
}

/**
 * Parse a full message as a slash command invocation.
 * Only matches when the entire message (after trim) is `/cmd` or `/cmd args`.
 */
export function parseSlashInvocation(text: string): { name: string; args: string } | null {
  const trimmed = text.trim();
  if (!trimmed.startsWith("/")) return null;
  // Reject multi-line pure-command for v1 (body with newlines after first line is still ok as args)
  const match = trimmed.match(/^\/(\S+)(?:\s+([\s\S]*))?$/);
  if (!match) return null;
  return {
    name: match[1],
    args: (match[2] ?? "").trimEnd(),
  };
}
