/**
 * Unit tests for cli/diffFilter.js — parseGitDiff.
 *
 * Only the pure parsing function is tested here; buildChangedLinesMap requires
 * a live git subprocess and is covered by integration testing.
 */

import * as path from "path";
import { parseGitDiff } from "../../../cli/diffFilter.js";

const REPO_ROOT = path.join("/", "repo"); // platform-neutral absolute path for tests

describe("parseGitDiff", () => {
    test("returns empty map for empty diff output", () => {
        expect(parseGitDiff("", REPO_ROOT).size).toBe(0);
    });

    test("returns empty map for diff with no +++ lines", () => {
        const diff = "diff --git a/file.TXT b/file.TXT\nindex abc..def 100644\n";
        expect(parseGitDiff(diff, REPO_ROOT).size).toBe(0);
    });

    test("single hunk: adds the correct 0-based line indices", () => {
        // @@ -0,0 +1,3 @@ — lines 1, 2, 3 in new file → indices 0, 1, 2
        const diff = [
            "diff --git a/src/foo.TXT b/src/foo.TXT",
            "--- a/src/foo.TXT",
            "+++ b/src/foo.TXT",
            "@@ -0,0 +1,3 @@",
            "+line one",
            "+line two",
            "+line three"
        ].join("\n");

        const map = parseGitDiff(diff, REPO_ROOT);
        const absPath = path.join(REPO_ROOT, "src/foo.TXT");
        expect(map.has(absPath)).toBe(true);
        expect(map.get(absPath)).toEqual(new Set([0, 1, 2]));
    });

    test("hunk with omitted count defaults to 1 line", () => {
        // @@ -5 +5 @@ — count omitted, means 1 line → index 4
        const diff = [
            "+++ b/src/bar.TXT",
            "@@ -5 +5 @@",
            "+changed line"
        ].join("\n");

        const map = parseGitDiff(diff, REPO_ROOT);
        const absPath = path.join(REPO_ROOT, "src/bar.TXT");
        expect(map.get(absPath)).toEqual(new Set([4]));
    });

    test("deletion-only hunk (count=0) adds no lines", () => {
        // @@ -3,2 +3,0 @@ — 2 lines deleted, 0 added
        const diff = [
            "+++ b/src/baz.TXT",
            "@@ -3,2 +3,0 @@",
            "-removed line 1",
            "-removed line 2"
        ].join("\n");

        const map = parseGitDiff(diff, REPO_ROOT);
        const absPath = path.join(REPO_ROOT, "src/baz.TXT");
        // File appears in map but set is empty
        expect(map.has(absPath)).toBe(true);
        expect(map.get(absPath).size).toBe(0);
    });

    test("multiple hunks in one file accumulate into the same Set", () => {
        // Hunk 1: +1,2 → indices 0, 1
        // Hunk 2: +10,1 → index 9
        const diff = [
            "+++ b/src/multi.TXT",
            "@@ -0,0 +1,2 @@",
            "+first",
            "+second",
            "@@ -15 +10,1 @@",
            "+third"
        ].join("\n");

        const map = parseGitDiff(diff, REPO_ROOT);
        const absPath = path.join(REPO_ROOT, "src/multi.TXT");
        expect(map.get(absPath)).toEqual(new Set([0, 1, 9]));
    });

    test("multiple files each get their own Set", () => {
        const diff = [
            "+++ b/src/alpha.TXT",
            "@@ -0,0 +1 @@",
            "+alpha line",
            "+++ b/src/beta.TXT",
            "@@ -0,0 +3,2 @@",
            "+beta line 1",
            "+beta line 2"
        ].join("\n");

        const map = parseGitDiff(diff, REPO_ROOT);
        expect(map.size).toBe(2);
        expect(map.get(path.join(REPO_ROOT, "src/alpha.TXT"))).toEqual(new Set([0]));
        expect(map.get(path.join(REPO_ROOT, "src/beta.TXT"))).toEqual(new Set([2, 3]));
    });

    test("line 1 in diff output maps to index 0 (1-to-0-based conversion)", () => {
        const diff = ["+++ b/convert.TXT", "@@ -0,0 +1 @@", "+only line"].join("\n");
        const map = parseGitDiff(diff, REPO_ROOT);
        expect(map.get(path.join(REPO_ROOT, "convert.TXT"))).toEqual(new Set([0]));
    });

    test("hunk header with trailing description text is still parsed", () => {
        // Real git often appends the surrounding function name after @@
        const diff = [
            "+++ b/src/func.TXT",
            "@@ -20,0 +21,2 @@ FUNCTION Foo():STRING",
            "+new line 1",
            "+new line 2"
        ].join("\n");

        const map = parseGitDiff(diff, REPO_ROOT);
        expect(map.get(path.join(REPO_ROOT, "src/func.TXT"))).toEqual(new Set([20, 21]));
    });
});
