import type { FileDiff, FileChangeType, DiffHunk, DiffLine } from "./types";

/**
 * Parse a unified diff string into structured FileDiff objects.
 */
export function parseUnifiedDiff(raw: string): FileDiff[] {
  const files: FileDiff[] = [];
  const fileChunks = raw.split(/^diff --git /m).filter(Boolean);

  for (const chunk of fileChunks) {
    const lines = chunk.split("\n");

    // Extract paths from first line: "a/path b/path"
    const headerMatch = lines[0]?.match(/^a\/(.+?) b\/(.+)$/);
    if (!headerMatch) continue;

    const oldPath = headerMatch[1];
    const newPath = headerMatch[2];
    const hunks: DiffHunk[] = [];
    let additions = 0;
    let deletions = 0;

    // Scan header lines (between "diff --git" and first "@@") for /dev/null markers
    let hasOldDevNull = false;
    let hasNewDevNull = false;
    let i = 1;
    while (i < lines.length && !lines[i].startsWith("@@")) {
      if (lines[i].startsWith("--- /dev/null")) hasOldDevNull = true;
      if (lines[i].startsWith("+++ /dev/null")) hasNewDevNull = true;
      i++;
    }

    while (i < lines.length) {
      const hunkMatch = lines[i].match(
        /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/
      );
      if (!hunkMatch) {
        i++;
        continue;
      }

      const oldStart = parseInt(hunkMatch[1], 10);
      const oldCount = parseInt(hunkMatch[2] ?? "1", 10);
      const newStart = parseInt(hunkMatch[3], 10);
      const newCount = parseInt(hunkMatch[4] ?? "1", 10);
      const header = lines[i];

      const hunkLines: DiffLine[] = [];
      let oldLine = oldStart;
      let newLine = newStart;

      i++;
      while (i < lines.length && !lines[i].startsWith("@@") && !lines[i].startsWith("diff --git ")) {
        const line = lines[i];
        if (line.startsWith("+")) {
          hunkLines.push({
            type: "added",
            content: line.slice(1),
            oldLineNumber: null,
            newLineNumber: newLine,
          });
          newLine++;
          additions++;
        } else if (line.startsWith("-")) {
          hunkLines.push({
            type: "removed",
            content: line.slice(1),
            oldLineNumber: oldLine,
            newLineNumber: null,
          });
          oldLine++;
          deletions++;
        } else if (line.startsWith(" ") || line === "") {
          hunkLines.push({
            type: "context",
            content: line.startsWith(" ") ? line.slice(1) : line,
            oldLineNumber: oldLine,
            newLineNumber: newLine,
          });
          oldLine++;
          newLine++;
        } else {
          // Likely "\ No newline at end of file" or similar
          i++;
          continue;
        }
        i++;
      }

      hunks.push({ header, oldStart, oldCount, newStart, newCount, lines: hunkLines });
    }

    // Derive changeType from header markers and path comparison
    let changeType: FileChangeType;
    if (hasOldDevNull) {
      changeType = "added";
    } else if (hasNewDevNull) {
      changeType = "deleted";
    } else if (oldPath !== newPath) {
      changeType = "renamed";
    } else {
      changeType = "modified";
    }

    files.push({ oldPath, newPath, hunks, additions, deletions, changeType });
  }

  return files;
}
