import json
import shutil
from datetime import datetime, timezone
from pathlib import Path
from typing import Dict, List

from tenant_manager import tenant_paths


SNAPSHOT_FILES = ["risk", "release", "runtime"]


def _now_tag() -> str:
    return datetime.now(timezone.utc).strftime("%Y%m%d%H%M%S")


def _snapshot_root(project_root: Path, tenant_id: str) -> Path:
    tid = tenant_id or "default"
    return project_root / "tenants" / tid / "snapshots"


def _manifest_path(project_root: Path, tenant_id: str) -> Path:
    return _snapshot_root(project_root, tenant_id) / "manifest.json"


def _load_manifest(project_root: Path, tenant_id: str) -> Dict[str, object]:
    path = _manifest_path(project_root, tenant_id)
    if not path.exists():
        return {"current": "", "snapshots": []}
    return json.loads(path.read_text(encoding="utf-8"))


def _save_manifest(project_root: Path, tenant_id: str, manifest: Dict[str, object]) -> None:
    path = _manifest_path(project_root, tenant_id)
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")


def create_snapshot(project_root: Path, tenant_id: str, reason: str = "") -> Dict[str, object]:
    paths = tenant_paths(project_root, tenant_id)
    tag = _now_tag()
    root = _snapshot_root(project_root, tenant_id)
    snap_dir = root / tag
    snap_dir.mkdir(parents=True, exist_ok=True)
    copied = []
    for key in SNAPSHOT_FILES:
        src = paths[key]
        if not src.exists():
            continue
        dst = snap_dir / f"{key}.json"
        shutil.copy2(src, dst)
        copied.append(key)
    manifest = _load_manifest(project_root, tenant_id)
    snapshots: List[Dict[str, object]] = list(manifest.get("snapshots", []))  # type: ignore[arg-type]
    snapshots.append({"tag": tag, "reason": reason, "ts": datetime.now(timezone.utc).isoformat(), "files": copied})
    manifest["snapshots"] = snapshots
    manifest["current"] = tag
    _save_manifest(project_root, tenant_id, manifest)
    return {"tenant_id": tenant_id or "default", "tag": tag, "files": copied}


def list_snapshots(project_root: Path, tenant_id: str) -> Dict[str, object]:
    manifest = _load_manifest(project_root, tenant_id)
    return {"tenant_id": tenant_id or "default", "manifest": manifest}


def rollback_snapshot(project_root: Path, tenant_id: str, tag: str) -> Dict[str, object]:
    paths = tenant_paths(project_root, tenant_id)
    root = _snapshot_root(project_root, tenant_id)
    snap_dir = root / tag
    if not snap_dir.exists():
        raise ValueError("SNAPSHOT_NOT_FOUND")
    restored = []
    for key in SNAPSHOT_FILES:
        src = snap_dir / f"{key}.json"
        if not src.exists():
            continue
        dst = paths[key]
        dst.parent.mkdir(parents=True, exist_ok=True)
        shutil.copy2(src, dst)
        restored.append(key)
    manifest = _load_manifest(project_root, tenant_id)
    manifest["current"] = tag
    _save_manifest(project_root, tenant_id, manifest)
    return {"tenant_id": tenant_id or "default", "tag": tag, "restored": restored}
