"""Voice profile loader.

The comedian's voice profile is a JSON file loaded at runtime from
`VOICE_PROFILES_DIR/<comedian_id>.json`. No voice-profile artifact existed in
the workstation prior to this repo, so a baseline `max-amini.json` is seeded
in `voice_profiles/`.

In a later phase the director can be pointed at any external artifact by
changing `VOICE_PROFILES_DIR` — the loader interface does not change.
"""

from __future__ import annotations

import json
import logging
from pathlib import Path
from typing import Any

from app.config import settings
from app.models import VoiceProfile

logger = logging.getLogger(__name__)


class VoiceProfileNotFound(FileNotFoundError):
    pass


def _resolve_dir() -> Path:
    return Path(settings.VOICE_PROFILES_DIR).resolve()


def load_voice_profile(comedian_id: str | None = None) -> VoiceProfile:
    comedian_id = comedian_id or settings.DEFAULT_COMEDIAN_ID
    directory = _resolve_dir()
    path = directory / f"{comedian_id}.json"
    if not path.is_file():
        logger.error("voice profile not found: %s", path)
        raise VoiceProfileNotFound(f"voice profile not found: {path}")
    raw: dict[str, Any] = json.loads(path.read_text(encoding="utf-8"))
    # Tolerate either {"comedian_id": "...", ...} or {"id": "..."} shapes.
    raw.setdefault("comedian_id", comedian_id)
    raw.pop("id", None)
    return VoiceProfile.model_validate(raw)


def available_voice_profiles() -> list[str]:
    directory = _resolve_dir()
    if not directory.is_dir():
        return []
    return [p.stem for p in directory.glob("*.json") if p.is_file()]