#!/usr/bin/env python3
"""
Merge a friend's reviewed (checked) diffs into your diff JSON files.

The friend exports "Export Checked" from the review HTML — that file
contains only the diffs they confirmed as real editorial changes.
This script replaces each volume's diffs with only the confirmed ones.

Always reads from the .json.bak originals, so multiple reviews can be
merged safely. If two friends review the same volume, the intersection
(diffs confirmed by both) is kept.

Usage:
  python3 apply_review.py friend_export.json                # apply one review
  python3 apply_review.py friend1.json friend2.json         # merge (keep intersection)
  python3 apply_review.py friend_export.json --dry-run      # preview only
  python3 apply_review.py --restore                         # undo all reviews
"""

import json
import shutil
import sys
from pathlib import Path

REPORTS = Path(__file__).parent / "reports"


def diff_key(d):
    """Unique key for a diff entry."""
    return (d.get("original", ""), d.get("vedabase", ""), str(d.get("chapter", "")))


def ensure_backup(json_file):
    """Create a .json.bak backup if one doesn't exist yet."""
    backup = json_file.with_suffix(".json.bak")
    if not backup.exists():
        shutil.copy2(json_file, backup)
    return backup


def load_original(vol_key):
    """Always load from the backup (original) file if it exists."""
    json_file = REPORTS / f"{vol_key}_diffs.json"
    backup = json_file.with_suffix(".json.bak")
    source = backup if backup.exists() else json_file
    if not source.exists():
        return None, json_file
    with open(source) as f:
        return json.load(f), json_file


def apply(review_paths, dry_run=False):
    # Load all reviewed (checked) diffs from each file
    reviews = []
    for path in review_paths:
        print(f"Reading: {path}")
        with open(path) as f:
            reviews.append(json.load(f))

    # Find all volumes mentioned in any review
    all_vol_keys = set()
    for rev in reviews:
        all_vol_keys.update(rev.keys())

    total_before = 0
    total_after = 0

    for vol_key in sorted(all_vol_keys):
        report, json_file = load_original(vol_key)
        if report is None:
            print(f"  SKIP {vol_key}: file not found")
            continue

        before = len(report["differences"])
        total_before += before

        # Build set of confirmed diffs from each reviewer
        confirmed_sets = []
        for rev in reviews:
            if vol_key in rev:
                confirmed_sets.append({diff_key(d) for d in rev[vol_key]["diffs"]})

        if len(confirmed_sets) == 1:
            # Single reviewer: keep what they checked
            confirmed = confirmed_sets[0]
        else:
            # Multiple reviewers: keep intersection (confirmed by all)
            confirmed = confirmed_sets[0]
            for s in confirmed_sets[1:]:
                confirmed = confirmed & s

        # Filter original diffs to only confirmed ones
        kept = [d for d in report["differences"] if diff_key(d) in confirmed]
        removed = before - len(kept)
        total_after += len(kept)

        print(f"  {vol_key}: {before} -> {len(kept)} ({removed} removed)")

        if not dry_run and removed > 0:
            ensure_backup(json_file)
            report["differences"] = kept
            report["stats"]["total_diffs"] = len(kept)
            with open(json_file, "w") as f:
                json.dump(report, f, indent=2, ensure_ascii=False)

    print(f"\nResult: {total_before} original -> {total_after} confirmed ({total_before - total_after} removed)")
    if dry_run:
        print("(DRY RUN - no files changed)")


def restore():
    """Restore all .json.bak files back to .json (undo all reviews)."""
    count = 0
    for bak in sorted(REPORTS.glob("*_diffs.json.bak")):
        target = bak.with_suffix("")
        shutil.copy2(bak, target)
        count += 1
        print(f"  Restored {target.name}")
    if count == 0:
        print("No backups found -- nothing to restore.")
    else:
        print(f"\nRestored {count} files to original state.")


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(__doc__)
        sys.exit(1)

    if "--restore" in sys.argv:
        restore()
        sys.exit(0)

    dry_run = "--dry-run" in sys.argv
    review_paths = [a for a in sys.argv[1:] if not a.startswith("--")]

    print(f"Reports dir: {REPORTS}")
    if dry_run:
        print("DRY RUN MODE")
    print()

    apply(review_paths, dry_run)
