"""VP perfect-distill export bundle — write to export_bundle/v{n}/ (M2)."""

from __future__ import annotations

import json
import re
import shutil
from datetime import datetime, timezone
from pathlib import Path
from typing import TYPE_CHECKING, Any

from niannian.virtual_persona.pack import read_pack, write_pack
from niannian.virtual_persona.perfect_distill import (
    PerfectDistillError,
    build_perfect_distill_preview,
    normalize_export_options,
)
from niannian.virtual_persona.stickers import MANIFEST_NAME as STICKER_MANIFEST_NAME

if TYPE_CHECKING:
    from niannian.virtual_persona.store import VirtualPersonaStore

EXPORT_BUNDLE_DIR = "export_bundle"
MANIFEST_SCHEMA_VERSION = 1
_VERSION_DIR_RE = re.compile(r"^v(\d+)$")


def _now_iso() -> str:
    return datetime.now(timezone.utc).isoformat()


def export_bundle_root(store: VirtualPersonaStore, vp_id: str) -> Path:
    return store.export_bundle_versions_dir(vp_id)


def _next_version(root: Path) -> int:
    highest = 0
    if root.is_dir():
        for child in root.iterdir():
            if not child.is_dir():
                continue
            match = _VERSION_DIR_RE.match(child.name)
            if match:
                highest = max(highest, int(match.group(1)))
    return highest + 1


def _write_json(path: Path, data: Any) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")


def _read_manifest(bundle_dir: Path) -> dict[str, Any] | None:
    manifest_path = bundle_dir / "manifest.json"
    if not manifest_path.is_file():
        return None
    try:
        with manifest_path.open(encoding="utf-8") as f:
            data = json.load(f)
    except (OSError, json.JSONDecodeError):
        return None
    return data if isinstance(data, dict) else None


def write_export_bundle(
    store: VirtualPersonaStore,
    vp_id: str,
    export_options: dict[str, Any] | None = None,
    *,
    preview: dict[str, Any] | None = None,
) -> Path:
    """Write export bundle under virtual_personas/{id}/export_bundle/v{n}/."""
    if preview is None:
        preview_result = build_perfect_distill_preview(store, vp_id, export_options)
        preview = preview_result["preview"]
    opts = normalize_export_options(export_options or preview.get("export_options"))

    root = store.ensure_export_bundle_dir(vp_id)
    version = _next_version(root)
    bundle_dir = root / f"v{version}"
    bundle_dir.mkdir(parents=True, exist_ok=False)

    files: list[str] = []

    profile_path = bundle_dir / "profile.md"
    profile_path.write_text(str(preview.get("profile_md") or ""), encoding="utf-8")
    files.append("profile.md")

    summary_path = bundle_dir / "assembly_summary.md"
    summary_path.write_text(str(preview.get("assembly_summary") or ""), encoding="utf-8")
    files.append("assembly_summary.md")

    if opts["include_full_l2"]:
        master_path = bundle_dir / "assembly_master.md"
        master_path.write_text(str(preview.get("assembly_master") or ""), encoding="utf-8")
        files.append("assembly_master.md")

    if opts["include_stickers"]:
        src_manifest = store.vp_dir(vp_id) / "stickers" / STICKER_MANIFEST_NAME
        dest_manifest = bundle_dir / "stickers" / STICKER_MANIFEST_NAME
        if src_manifest.is_file():
            dest_manifest.parent.mkdir(parents=True, exist_ok=True)
            shutil.copy2(src_manifest, dest_manifest)
            files.append(f"stickers/{STICKER_MANIFEST_NAME}")

    if opts["include_proactive_profile"] and "proactive_profile" in preview:
        _write_json(bundle_dir / "memory" / "proactive_profile.json", preview["proactive_profile"])
        files.append("memory/proactive_profile.json")

    if opts["include_deep_learn_runs"] and "deep_learn_runs" in preview:
        _write_json(bundle_dir / "deep_learn" / "runs.json", preview["deep_learn_runs"])
        files.append("deep_learn/runs.json")

    manifest = {
        "schema_version": MANIFEST_SCHEMA_VERSION,
        "version": version,
        "bundle_id": f"v{version}",
        "vp_id": preview.get("vp_id") or vp_id,
        "label": preview.get("label") or vp_id,
        "stage": preview.get("stage"),
        "created_at": _now_iso(),
        "export_options": opts,
        "files": files,
    }
    (bundle_dir / "manifest.json").write_text(
        json.dumps(manifest, ensure_ascii=False, indent=2) + "\n",
        encoding="utf-8",
    )

    pack = read_pack(store, vp_id)
    pack["export_latest"] = version
    pack["updated_at"] = _now_iso()
    write_pack(store, vp_id, pack)

    return bundle_dir


def list_export_bundles(store: VirtualPersonaStore, vp_id: str) -> list[dict[str, Any]]:
    """List export bundles newest-first."""
    root = export_bundle_root(store, vp_id)
    if not root.is_dir():
        return []

    rows: list[dict[str, Any]] = []
    for child in sorted(root.iterdir(), key=lambda p: p.name):
        if not child.is_dir():
            continue
        match = _VERSION_DIR_RE.match(child.name)
        if not match:
            continue
        version = int(match.group(1))
        manifest = _read_manifest(child) or {}
        rows.append(
            {
                "bundle_id": manifest.get("bundle_id") or child.name,
                "version": manifest.get("version", version),
                "created_at": manifest.get("created_at"),
                "export_options": manifest.get("export_options") or {},
                "files": list(manifest.get("files") or []),
                "path": str(child),
            }
        )
    rows.sort(key=lambda row: int(row.get("version") or 0), reverse=True)
    return rows


def bundle_id_from_path(bundle_dir: Path) -> str:
    match = _VERSION_DIR_RE.match(bundle_dir.name)
    if match:
        return f"v{match.group(1)}"
    raise PerfectDistillError(f"invalid export bundle path: {bundle_dir}")
