/**
 * 基于 LCS 的行级 diff，返回左右两侧需要高亮的行号（0-based）
 */
export function diffLines(oldStr, newStr) {
  const oldLines = (oldStr || "").split("\n");
  const newLines = (newStr || "").split("\n");
  const m = oldLines.length;
  const n = newLines.length;
  const dp = buildLcsDp(oldLines, newLines);

  const oldMarks = [];
  const newMarks = [];
  const rawOps = [];
  let i = m;
  let j = n;

  while (i > 0 || j > 0) {
    if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
      rawOps.unshift({ type: "eq", old: i - 1, new: j - 1 });
      i--;
      j--;
    } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
      newMarks.unshift(j - 1);
      rawOps.unshift({ type: "ins", new: j - 1 });
      j--;
    } else {
      oldMarks.unshift(i - 1);
      rawOps.unshift({ type: "del", old: i - 1 });
      i--;
    }
  }

  const diffNavList = buildDiffHunks(rawOps);

  return { oldMarks, newMarks, diffNavList };
}

function buildLcsDp(oldLines, newLines) {
  const m = oldLines.length;
  const n = newLines.length;
  const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));

  for (let i = 1; i <= m; i++) {
    for (let j = 1; j <= n; j++) {
      if (oldLines[i - 1] === newLines[j - 1]) {
        dp[i][j] = dp[i - 1][j - 1] + 1;
      } else {
        dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
      }
    }
  }

  return dp;
}

function buildDiffHunks(rawOps) {
  const hunks = [];
  let hunk = null;
  let lastEqOld = -1;
  let lastEqNew = -1;

  rawOps.forEach((op) => {
    if (op.type === "eq") {
      if (hunk) {
        hunks.push(finalizeHunk(hunk, lastEqOld, lastEqNew));
        hunk = null;
      }
      lastEqOld = op.old;
      lastEqNew = op.new;
      return;
    }

    if (!hunk) {
      hunk = { left: null, right: null, leftEnd: null, rightEnd: null };
    }

    if (op.type === "del") {
      if (hunk.left == null) hunk.left = op.old;
      hunk.leftEnd = op.old;
    } else {
      if (hunk.right == null) hunk.right = op.new;
      hunk.rightEnd = op.new;
    }
  });

  if (hunk) {
    hunks.push(finalizeHunk(hunk, lastEqOld, lastEqNew));
  }

  return hunks;
}

function finalizeHunk(hunk, lastEqOld, lastEqNew) {
  return {
    left: hunk.left,
    right: hunk.right,
    leftEnd: hunk.leftEnd,
    rightEnd: hunk.rightEnd,
    anchorLeft: Math.max(lastEqOld, 0),
    anchorRight: Math.max(lastEqNew, 0),
  };
}
