#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
compare_file_diff.py

compare_update_diff.py から、2つのテキストファイルのdiff機能だけを
抜き出したプログラム。

第1位置引数: old_file
第2位置引数: new_file

例:
    python compare_file_diff.py old.py new.py
    python compare_file_diff.py old.py new.py --context 3
"""

import argparse
import difflib
from pathlib import Path


def read_text_lines(path):
    """
    テキストファイルを読み込み、行リストと文字コードを返す。

    UTF-8を優先し、日本語Windows環境を考慮してcp932も試す。
    改行コードは universal newline で正規化するため、
    CRLF/LFの違いだけではdiffにならない。
    """
    encodings = ("utf-8-sig", "utf-8", "cp932")

    for enc in encodings:
        try:
            with open(path, "r", encoding=enc) as f:
                return f.readlines(), enc
        except UnicodeDecodeError:
            pass

    with open(path, "r", encoding="utf-8", errors="replace") as f:
        return f.readlines(), "utf-8(replace)"


def make_compact_diff(old_path, new_path, context=2):
    """
    compact diffを作る。

    - 実際の変更行 (+/-)
    - その前後のcontext行
    だけを出力する。

    unified diffの
      --- / +++ / @@
    は表示しない。

    離れた変更箇所は "..." で区切る。
    """
    old_lines, old_enc = read_text_lines(old_path)
    new_lines, new_enc = read_text_lines(new_path)

    diff_lines = list(
        difflib.unified_diff(
            old_lines,
            new_lines,
            fromfile=str(old_path),
            tofile=str(new_path),
            n=max(0, int(context)),
            lineterm="\n",
        )
    )

    compact = []
    seen_hunk = False

    for line in diff_lines:
        if line.startswith("--- ") or line.startswith("+++ "):
            continue

        if line.startswith("@@ "):
            if seen_hunk and compact and compact[-1] != "...":
                compact.append("...")
            seen_hunk = True
            continue

        if line.startswith("\\ No newline at end of file"):
            continue

        if line.endswith("\n"):
            line = line[:-1]

        compact.append(line)

    while compact and compact[0] == "...":
        compact.pop(0)
    while compact and compact[-1] == "...":
        compact.pop()

    return compact, old_enc, new_enc


def main():
    parser = argparse.ArgumentParser(
        description="Show a compact text diff between two files."
    )
    parser.add_argument(
        "old_file",
        help="Old/reference file",
    )
    parser.add_argument(
        "new_file",
        help="New/current file",
    )
    parser.add_argument(
        "--context", "-c",
        type=int,
        default=2,
        help="Number of unchanged context lines around each change (default: 2)",
    )

    args = parser.parse_args()

    old_path = Path(args.old_file).expanduser().resolve()
    new_path = Path(args.new_file).expanduser().resolve()

    if not old_path.is_file():
        parser.error(f"old_file is not found: {old_path}")

    if not new_path.is_file():
        parser.error(f"new_file is not found: {new_path}")

    diff_lines, old_enc, new_enc = make_compact_diff(
        old_path,
        new_path,
        context=max(0, args.context),
    )

    print(f"old: {old_path} ({old_enc})")
    print(f"new: {new_path} ({new_enc})")
    print(f"context: {max(0, args.context)}")
    print("---")

    if diff_lines:
        print("\n".join(diff_lines))
    else:
        print("(no text difference found)")


if __name__ == "__main__":
    main()
