/**
 * Insert markdown snippets into a textarea at the current cursor position.
 * Handles selection-aware insertion (wrapping selected text).
 */

export interface TextareaInsertResult {
  newValue: string;
  cursorPos: number;
}

export function insertAtCursor(
  textarea: HTMLTextAreaElement,
  before: string,
  after: string,
): TextareaInsertResult {
  const { selectionStart, selectionEnd, value } = textarea;
  const selected = value.substring(selectionStart, selectionEnd);

  if (selected) {
    // Wrap selection
    const inserted = before + selected + after;
    const newValue = value.substring(0, selectionStart) + inserted + value.substring(selectionEnd);
    return { newValue, cursorPos: selectionStart + inserted.length };
  }

  // No selection — insert markers and position cursor between them
  const inserted = before + after;
  const newValue = value.substring(0, selectionStart) + inserted + value.substring(selectionEnd);
  return { newValue, cursorPos: selectionStart + before.length };
}

export function insertBlock(
  textarea: HTMLTextAreaElement,
  template: string,
): TextareaInsertResult {
  const { selectionStart, selectionEnd, value } = textarea;
  const selected = value.substring(selectionStart, selectionEnd);

  let text = template.replace('$CURSOR', selected || '');

  // If cursor is in the middle of a line, prepend newline
  const lineStart = value.lastIndexOf('\n', selectionStart - 1) + 1;
  const beforeCursor = value.substring(lineStart, selectionStart);
  if (beforeCursor.trim().length > 0) {
    text = '\n' + text;
  }

  const newValue = value.substring(0, selectionStart) + text + value.substring(selectionEnd);
  const cursorMarker = text.indexOf(selected || '');
  const cursorPos = selectionStart + (cursorMarker >= 0 ? cursorMarker + (selected || '').length : text.length);
  return { newValue, cursorPos };
}

/**
 * Cycle heading level at the current line.
 * No heading -> # -> ## -> ### -> remove heading
 */
export function cycleHeading(textarea: HTMLTextAreaElement): TextareaInsertResult {
  const { selectionStart, value } = textarea;

  // Find the current line
  const lineStart = value.lastIndexOf('\n', selectionStart - 1) + 1;
  const lineEnd = value.indexOf('\n', selectionStart);
  const line = value.substring(lineStart, lineEnd === -1 ? value.length : lineEnd);

  const match = line.match(/^(#{1,3})\s/);
  let newLine: string;
  if (!match) {
    newLine = '# ' + line;
  } else if (match[1] === '#') {
    newLine = '## ' + line.substring(2);
  } else if (match[1] === '##') {
    newLine = '### ' + line.substring(3);
  } else {
    // ### -> remove
    newLine = line.substring(4);
  }

  const end = lineEnd === -1 ? value.length : lineEnd;
  const newValue = value.substring(0, lineStart) + newLine + value.substring(end);
  const cursorPos = lineStart + newLine.length;
  return { newValue, cursorPos };
}

/**
 * Apply a textarea snippet result: update value and set cursor position.
 */
export function applyResult(
  textarea: HTMLTextAreaElement,
  result: TextareaInsertResult,
  onChange: (value: string) => void,
): void {
  onChange(result.newValue);
  // Use requestAnimationFrame so React has time to update the textarea value
  requestAnimationFrame(() => {
    textarea.focus();
    textarea.setSelectionRange(result.cursorPos, result.cursorPos);
  });
}
