#!/usr/bin/env python3
"""
Compare captured outputs from different branches or configurations.

This script loads two captured recordings and compares them frame-by-frame,
reporting any differences found.
"""

import argparse
import difflib
import json
from pathlib import Path


def load_recording(file_path: str) -> dict:
    """Load a recording from a JSON file."""
    with open(file_path, "r") as f:
        return json.load(f)


def compare_frame_buffers(buf1: list[str], buf2: list[str]) -> tuple[int, list[str]]:
    """Compare two frame buffers and return differences.

    Returns:
        tuple: (difference_count, list of difference descriptions)
    """
    differences = []

    # Check dimensions
    if len(buf1) != len(buf2):
        differences.append(f"Height mismatch: {len(buf1)} vs {len(buf2)}")

    # Check each line
    max_lines = max(len(buf1), len(buf2))
    for i in range(max_lines):
        if i >= len(buf1):
            differences.append(f"Line {i}: Missing in first buffer")
            continue
        if i >= len(buf2):
            differences.append(f"Line {i}: Missing in second buffer")
            continue

        line1 = buf1[i]
        line2 = buf2[i]

        if line1 != line2:
            # Find the specific differences in the line
            if len(line1) != len(line2):
                differences.append(
                    f"Line {i}: Length mismatch ({len(line1)} vs {len(line2)})"
                )

            # Show a snippet of the difference
            max_len = max(len(line1), len(line2))
            snippet1 = line1[:50] + "..." if len(line1) > 50 else line1
            snippet2 = line2[:50] + "..." if len(line2) > 50 else line2
            differences.append(f"Line {i}: '{snippet1}' != '{snippet2}'")

    return len(differences), differences


def compare_recordings(
    recording1: dict, recording2: dict, max_frames: int = None
) -> dict:
    """Compare two recordings frame-by-frame.

    Returns:
        dict: Comparison results with summary and detailed differences
    """
    results = {
        "summary": {},
        "frames": [],
        "total_differences": 0,
        "frames_with_differences": 0,
    }

    # Compare metadata
    results["summary"]["recording1"] = {
        "preset": recording1.get("preset", "unknown"),
        "frame_count": recording1.get("frame_count", 0),
        "width": recording1.get("width", 0),
        "height": recording1.get("height", 0),
    }
    results["summary"]["recording2"] = {
        "preset": recording2.get("preset", "unknown"),
        "frame_count": recording2.get("frame_count", 0),
        "width": recording2.get("width", 0),
        "height": recording2.get("height", 0),
    }

    # Compare frames
    frames1 = recording1.get("frames", [])
    frames2 = recording2.get("frames", [])

    num_frames = min(len(frames1), len(frames2))
    if max_frames:
        num_frames = min(num_frames, max_frames)

    print(f"Comparing {num_frames} frames...")

    for frame_idx in range(num_frames):
        frame1 = frames1[frame_idx]
        frame2 = frames2[frame_idx]

        buf1 = frame1.get("buffer", [])
        buf2 = frame2.get("buffer", [])

        diff_count, differences = compare_frame_buffers(buf1, buf2)

        if diff_count > 0:
            results["total_differences"] += diff_count
            results["frames_with_differences"] += 1
            results["frames"].append(
                {
                    "frame_number": frame_idx,
                    "differences": differences,
                    "diff_count": diff_count,
                }
            )

            if frame_idx < 5:  # Only print first 5 frames with differences
                print(f"\nFrame {frame_idx} ({diff_count} differences):")
                for diff in differences[:5]:  # Limit to 5 differences per frame
                    print(f"  - {diff}")

    # Summary
    results["summary"]["total_frames_compared"] = num_frames
    results["summary"]["frames_with_differences"] = results["frames_with_differences"]
    results["summary"]["total_differences"] = results["total_differences"]
    results["summary"]["match_percentage"] = (
        (1 - results["frames_with_differences"] / num_frames) * 100
        if num_frames > 0
        else 0
    )

    return results


def print_comparison_summary(results: dict):
    """Print a summary of the comparison results."""
    print("\n" + "=" * 80)
    print("COMPARISON SUMMARY")
    print("=" * 80)

    r1 = results["summary"]["recording1"]
    r2 = results["summary"]["recording2"]

    print(f"\nRecording 1: {r1['preset']}")
    print(
        f"  Frames: {r1['frame_count']}, Width: {r1['width']}, Height: {r1['height']}"
    )

    print(f"\nRecording 2: {r2['preset']}")
    print(
        f"  Frames: {r2['frame_count']}, Width: {r2['width']}, Height: {r2['height']}"
    )

    print(f"\nComparison:")
    print(f"  Frames compared: {results['summary']['total_frames_compared']}")
    print(f"  Frames with differences: {results['summary']['frames_with_differences']}")
    print(f"  Total differences: {results['summary']['total_differences']}")
    print(f"  Match percentage: {results['summary']['match_percentage']:.2f}%")

    if results["summary"]["match_percentage"] == 100:
        print("\n✓ Recordings match perfectly!")
    else:
        print("\n⚠ Recordings have differences.")


def main():
    parser = argparse.ArgumentParser(
        description="Compare captured outputs from different branches"
    )
    parser.add_argument(
        "recording1",
        help="First recording file (JSON)",
    )
    parser.add_argument(
        "recording2",
        help="Second recording file (JSON)",
    )
    parser.add_argument(
        "--max-frames",
        type=int,
        help="Maximum number of frames to compare",
    )
    parser.add_argument(
        "--output",
        "-o",
        help="Output file for detailed comparison results (JSON)",
    )

    args = parser.parse_args()

    # Load recordings
    print(f"Loading {args.recording1}...")
    recording1 = load_recording(args.recording1)

    print(f"Loading {args.recording2}...")
    recording2 = load_recording(args.recording2)

    # Compare
    results = compare_recordings(recording1, recording2, args.max_frames)

    # Print summary
    print_comparison_summary(results)

    # Save detailed results if requested
    if args.output:
        output_path = Path(args.output)
        output_path.parent.mkdir(parents=True, exist_ok=True)
        with open(output_path, "w") as f:
            json.dump(results, f, indent=2)
        print(f"\nDetailed results saved to {args.output}")

    return 0


if __name__ == "__main__":
    exit(main())
