#!/usr/bin/env python3
"""Generate line-by-line diff between two markdown files."""

from __future__ import annotations

import argparse
import difflib
from pathlib import Path


def read_lines(path: Path) -> list[str]:
    text = path.read_text(encoding="utf-8-sig")
    return text.splitlines()


def generate_line_diff(src: Path, dst: Path) -> str:
    src_lines = read_lines(src)
    dst_lines = read_lines(dst)
    src_name = src.as_posix()
    dst_name = dst.as_posix()
    diff = difflib.unified_diff(
        src_lines,
        dst_lines,
        fromfile=src_name,
        tofile=dst_name,
        lineterm="",
    )
    return "\n".join(diff)


def generate_compact_line_diff(src: Path, dst: Path, context: int = 2) -> str:
    """Generate a compact diff showing only changed lines with a little context."""
    src_lines = read_lines(src)
    dst_lines = read_lines(dst)
    src_name = src.as_posix()
    dst_name = dst.as_posix()

    sm = difflib.SequenceMatcher(None, src_lines, dst_lines)
    output = [f"--- {src_name}", f"+++ {dst_name}", ""]

    for tag, i1, i2, j1, j2 in sm.get_opcodes():
        if tag == "equal":
            # Show only a few context lines around changes
            if context > 0:
                ctx = src_lines[i1:i2]
                if len(ctx) <= context * 2 + 1:
                    for line in ctx:
                        output.append(f" {line}")
                else:
                    for line in ctx[:context]:
                        output.append(f" {line}")
                    output.append(" ...")
                    for line in ctx[-context:]:
                        output.append(f" {line}")
        elif tag == "replace":
            output.append(f"@@ -{i1 + 1},{i2 - i1} +{j1 + 1},{j2 - j1} @@")
            for line in src_lines[i1:i2]:
                output.append(f"-{line}")
            for line in dst_lines[j1:j2]:
                output.append(f"+{line}")
        elif tag == "delete":
            output.append(f"@@ -{i1 + 1},{i2 - i1} +{j1 + 1},0 @@")
            for line in src_lines[i1:i2]:
                output.append(f"-{line}")
        elif tag == "insert":
            output.append(f"@@ -{i1 + 1},0 +{j1 + 1},{j2 - j1} @@")
            for line in dst_lines[j1:j2]:
                output.append(f"+{line}")

    return "\n".join(output)


def main() -> int:
    parser = argparse.ArgumentParser(description="Generate line-by-line diff for markdown files.")
    parser.add_argument("--input-dir", type=Path, required=True, help="Directory containing source files.")
    parser.add_argument("--output-dir", type=Path, required=True, help="Directory containing polished files.")
    parser.add_argument("--out-diff-dir", type=Path, required=True, help="Directory to write diff files.")
    parser.add_argument("--compact", action="store_true", help="Show only changed lines with context.")
    parser.add_argument("--context", type=int, default=2, help="Number of context lines around changes (compact mode).")
    args = parser.parse_args()

    args.out_diff_dir.mkdir(parents=True, exist_ok=True)

    for src in sorted(args.input_dir.glob("*.md")):
        dst = args.output_dir / src.name
        if not dst.exists():
            print(f"Skip {src.name}: no matching polished file.")
            continue

        if args.compact:
            diff_text = generate_compact_line_diff(src, dst, context=args.context)
            suffix = "-compact.diff"
        else:
            diff_text = generate_line_diff(src, dst)
            suffix = "-line.diff"

        out_path = args.out_diff_dir / (src.stem + suffix)
        out_path.write_text(diff_text, encoding="utf-8")
        print(f"Wrote {out_path}")

    return 0


if __name__ == "__main__":
    raise SystemExit(main())
