"""VP 私有贴纸 manifest — virtual_personas/{vp_id}/stickers/."""

from __future__ import annotations

import re
from pathlib import Path
from typing import TYPE_CHECKING, Any

import yaml

if TYPE_CHECKING:
    from niannian.virtual_persona.store import VirtualPersonaStore

MANIFEST_NAME = "manifest.yaml"


def _stickers_dir(vp_dir: Path) -> Path:
    return vp_dir / "stickers"


def _manifest_path(vp_dir: Path) -> Path:
    return _stickers_dir(vp_dir) / MANIFEST_NAME


def _default_manifest() -> dict[str, Any]:
    return {"version": 1, "stickers": []}


def _load_manifest(path: Path) -> dict[str, Any]:
    if not path.is_file():
        return _default_manifest()
    with path.open(encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    if not isinstance(data, dict):
        return _default_manifest()
    data.setdefault("version", 1)
    data.setdefault("stickers", [])
    if not isinstance(data["stickers"], list):
        data["stickers"] = []
    return data


def _save_manifest(path: Path, data: dict[str, Any]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    with path.open("w", encoding="utf-8") as f:
        yaml.safe_dump(data, f, allow_unicode=True, sort_keys=False)


def ensure_vp_sticker_dir(store: VirtualPersonaStore, vp_id: str) -> Path:
    """创建 virtual_personas/{id}/stickers/ 及空 manifest。"""
    dest = store.vp_dir(vp_id)
    stick_dir = _stickers_dir(dest)
    stick_dir.mkdir(parents=True, exist_ok=True)
    manifest = _manifest_path(dest)
    if not manifest.is_file():
        _save_manifest(manifest, _default_manifest())
    return stick_dir


def list_vp_stickers(store: VirtualPersonaStore, vp_id: str) -> list[dict[str, Any]]:
    """读取 VP manifest，返回 {slug, label, path, source, triggers}。"""
    dest = store.vp_dir(vp_id)
    stick_dir = _stickers_dir(dest)
    if not stick_dir.is_dir():
        return []
    manifest = _load_manifest(_manifest_path(dest))
    rows: list[dict[str, Any]] = []
    for entry in manifest.get("stickers") or []:
        if not isinstance(entry, dict):
            continue
        slug = str(entry.get("slug") or "").strip()
        if not slug:
            continue
        file_name = str(entry.get("file") or f"{slug}.png").strip() or f"{slug}.png"
        rows.append(
            {
                "slug": slug,
                "label": str(entry.get("label") or slug),
                "path": str(stick_dir / file_name),
                "source": str(entry.get("source") or "manifest"),
                "triggers": [str(t) for t in (entry.get("triggers") or []) if str(t).strip()],
            }
        )
    return rows


def vp_sticker_count(store: VirtualPersonaStore, vp_id: str) -> int:
    return len(list_vp_stickers(store, vp_id))


def _slugify(text: str) -> str:
    slug = re.sub(r"[^\w\-]+", "_", str(text or "sticker").strip())[:48]
    return slug.strip("_") or "sticker"


def _unique_slug(existing: set[str], base: str) -> str:
    slug = _slugify(base)
    if slug not in existing:
        return slug
    for idx in range(2, 100):
        candidate = f"{slug}_{idx}"
        if candidate not in existing:
            return candidate
    raise ValueError("sticker_slug_exhausted")


def add_vp_sticker_from_bytes(
    store: VirtualPersonaStore,
    vp_id: str,
    data: bytes,
    *,
    slug: str | None = None,
    label: str | None = None,
    source: str = "web_search",
    triggers: list[str] | None = None,
    source_url: str | None = None,
) -> dict[str, Any]:
    """Write PNG bytes into VP stickers/ and append manifest row."""
    if not data:
        raise ValueError("empty_image")
    dest = store.vp_dir(vp_id)
    stick_dir = ensure_vp_sticker_dir(store, vp_id)
    manifest_path = _manifest_path(dest)
    manifest = _load_manifest(manifest_path)
    stickers = [s for s in (manifest.get("stickers") or []) if isinstance(s, dict)]
    existing_slugs = {str(s.get("slug") or "").strip() for s in stickers if str(s.get("slug") or "").strip()}

    clean_label = str(label or "贴纸").strip()[:32] or "贴纸"
    sid = _unique_slug(existing_slugs, slug or clean_label)
    file_name = f"{sid}.png"
    (stick_dir / file_name).write_bytes(data)

    row: dict[str, Any] = {
        "slug": sid,
        "label": clean_label,
        "file": file_name,
        "source": str(source or "web_search"),
        "triggers": [str(t) for t in (triggers or []) if str(t).strip()],
    }
    if source_url:
        row["source_url"] = str(source_url)
    stickers.append(row)
    manifest["stickers"] = stickers
    _save_manifest(manifest_path, manifest)
    return {
        "slug": sid,
        "label": clean_label,
        "file": file_name,
        "source": row["source"],
        "triggers": row["triggers"],
    }
