import json
import shutil
from pathlib import Path
from typing import Optional, List, Dict, Any

from loguru import logger

from app.core.config import settings


BGM_EXTENSIONS = {".wav", ".mp3", ".m4a", ".aac", ".flac", ".ogg", ".webm"}


def _style_file_path(style_type: str) -> Path:
    return settings.ASSETS_DIR / "styles" / f"{style_type}.json"


def _load_style_file(style_type: str) -> List[Dict[str, Any]]:
    style_path = _style_file_path(style_type)
    if not style_path.exists():
        return []
    try:
        with open(style_path, "r", encoding="utf-8") as f:
            data = json.load(f)
            if isinstance(data, list):
                return data
    except Exception as e:
        logger.error(f"Failed to load style file {style_path}: {e}")
    return []


def list_styles(style_type: str) -> List[Dict[str, Any]]:
    return _load_style_file(style_type)


def get_style(style_type: str, style_id: Optional[str]) -> Optional[Dict[str, Any]]:
    if not style_id:
        return None
    for item in _load_style_file(style_type):
        if item.get("id") == style_id:
            return item
    return None


def get_default_style(style_type: str) -> Optional[Dict[str, Any]]:
    styles = _load_style_file(style_type)
    if not styles:
        return None
    for item in styles:
        if item.get("is_default"):
            return item
    return styles[0]


def list_bgm() -> List[Dict[str, Any]]:
    bgm_root = settings.ASSETS_DIR / "bgm"
    if not bgm_root.exists():
        return []

    items: List[Dict[str, Any]] = []
    for path in bgm_root.rglob("*"):
        if not path.is_file():
            continue
        if path.suffix.lower() not in BGM_EXTENSIONS:
            continue
        rel = path.relative_to(bgm_root).as_posix()
        items.append({
            "id": rel,
            "name": path.stem,
            "ext": path.suffix.lower().lstrip(".")
        })

    items.sort(key=lambda x: x.get("name", ""))
    return items


def resolve_bgm_path(bgm_id: str) -> Optional[Path]:
    if not bgm_id:
        return None
    bgm_root = settings.ASSETS_DIR / "bgm"
    candidate = (bgm_root / bgm_id).resolve()
    try:
        candidate.relative_to(bgm_root.resolve())
    except ValueError:
        return None
    if candidate.exists() and candidate.is_file():
        return candidate
    return None


def prepare_style_for_remotion(
    style: Optional[Dict[str, Any]],
    temp_dir: Path,
    prefix: str
) -> Optional[Dict[str, Any]]:
    if not style:
        return None

    prepared = dict(style)
    font_file = prepared.get("font_file")
    if not font_file:
        return prepared

    source_font = (settings.ASSETS_DIR / "fonts" / font_file).resolve()
    try:
        source_font.relative_to((settings.ASSETS_DIR / "fonts").resolve())
    except ValueError:
        logger.warning(f"Font path outside assets: {font_file}")
        return prepared

    if not source_font.exists():
        logger.warning(f"Font file missing: {source_font}")
        return prepared

    temp_dir.mkdir(parents=True, exist_ok=True)
    ext = source_font.suffix.lower()
    target_name = f"{prefix}{ext}"
    target_path = temp_dir / target_name

    try:
        shutil.copy(source_font, target_path)
        prepared["font_file"] = target_name
        if not prepared.get("font_family"):
            prepared["font_family"] = prefix
    except Exception as e:
        logger.warning(f"Failed to copy font {source_font} -> {target_path}: {e}")

    return prepared
