from __future__ import annotations

import hashlib
import json
from pathlib import Path
from typing import Any

from niannian.storage.manifest import utc_now_iso


def resolve_report_path(home: Path, cfg: dict[str, Any] | None = None) -> Path:
    ops = ((cfg or {}).get("storage") or {}).get("tier") or {}
    ops = ops.get("ops") or {}
    rel = ops.get("reconcile_report", "sync/reconcile_report.json")
    return (home / str(rel)).resolve()


def read_report(home: Path, cfg: dict[str, Any] | None = None) -> dict[str, Any]:
    path = resolve_report_path(home, cfg)
    if not path.is_file():
        return {
            "generated_at": None,
            "strategy_default": "newest_manifest_wins",
            "pending_conflicts": 0,
            "acknowledged": True,
            "conflicts": [],
        }
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
        data.setdefault("conflicts", [])
        data.setdefault("pending_conflicts", len(data["conflicts"]))
        return data
    except (json.JSONDecodeError, OSError):
        return {
            "generated_at": None,
            "strategy_default": "newest_manifest_wins",
            "pending_conflicts": 0,
            "acknowledged": True,
            "conflicts": [],
        }


def write_report(home: Path, report: dict[str, Any], *, cfg: dict[str, Any] | None = None) -> Path:
    path = resolve_report_path(home, cfg)
    path.parent.mkdir(parents=True, exist_ok=True)
    report = dict(report)
    report["pending_conflicts"] = len(report.get("conflicts") or [])
    path.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    return path


class ReconcileReporter:
    """记录 backfill 冲突 — 不改胜负逻辑。"""

    def __init__(self, home: Path, cfg: dict[str, Any] | None = None) -> None:
        self._home = home
        self._cfg = cfg or {}

    @property
    def path(self) -> Path:
        return resolve_report_path(self._home, self._cfg)

    def load(self) -> dict[str, Any]:
        return read_report(self._home, self._cfg)

    def record_conflict(
        self,
        *,
        rel_path: str,
        source_name: str,
        target_name: str,
        source_sha: str,
        target_sha: str,
        source_version: int,
        target_version: int,
        winner: str,
        reason: str,
    ) -> None:
        report = self.load()
        if report.get("acknowledged") is False and report.get("conflicts"):
            conflicts = list(report["conflicts"])
        else:
            conflicts = []
        entry = {
            "rel_path": rel_path,
            f"{source_name}_sha": source_sha[:16],
            f"{target_name}_sha": target_sha[:16],
            "winner": winner,
            "reason": reason,
            "source_version": source_version,
            "target_version": target_version,
        }
        if not any(c.get("rel_path") == rel_path and c.get("reason") == reason for c in conflicts):
            conflicts.append(entry)
        report = {
            "generated_at": utc_now_iso(),
            "strategy_default": "newest_manifest_wins",
            "pending_conflicts": len(conflicts),
            "acknowledged": False,
            "conflicts": conflicts,
        }
        write_report(self._home, report, cfg=self._cfg)

    def acknowledge(self) -> dict[str, Any]:
        report = self.load()
        report["acknowledged"] = True
        report["pending_conflicts"] = 0
        report["acknowledged_at"] = utc_now_iso()
        write_report(self._home, report, cfg=self._cfg)
        return report

    def health_summary(self) -> dict[str, Any]:
        report = self.load()
        pending = 0 if report.get("acknowledged") else int(report.get("pending_conflicts", 0))
        return {
            "pending_conflicts": pending,
            "acknowledged": bool(report.get("acknowledged", True)),
            "report_path": str(self.path.relative_to(self._home)),
            "last_at": report.get("generated_at"),
        }


def sha256_hex(data: bytes) -> str:
    return hashlib.sha256(data).hexdigest()
