# SonicForge Preset Library API — thư viện preset VST3 (.vstpreset) nằm trong
# storage/presets (mount qua volume trong docker; thư mục storage trên Windows).
#
# Vai trò: cầu nối Carla → pedalboard. User chỉnh preset trong Carla (native
# GUI) → xuất .vstpreset → upload vào thư viện → gán vào track (preset_id trong
# synth_engine) → render_engine tải qua load_preset → âm render = âm đã chỉnh.
import os
import uuid
import json
import time

from fastapi import APIRouter, HTTPException, UploadFile, File, Depends
from fastapi.responses import FileResponse
from typing import Optional

from app.core.vst_engine import preset_library_dir, PRESET_EXTENSIONS
from app.api.v1.auth import get_current_user, enforce_password_changed

router = APIRouter()


def _safe_preset_path(preset_id: str) -> str:
    """Chống path traversal: chỉ cho phép tên file (không chứa separator)."""
    if not preset_id or os.path.basename(preset_id) != preset_id:
        return ""
    d = preset_library_dir()
    p = os.path.join(d, preset_id)
    if os.path.isfile(p) and os.path.dirname(os.path.abspath(p)) == os.path.abspath(d):
        return p
    return ""


@router.get("")
async def list_presets():
    """Danh sách preset trong thư viện (public — frontend cần trước login)."""
    d = preset_library_dir()
    items = []
    try:
        names = sorted(os.listdir(d))
    except Exception:
        names = []
    for f in names:
        low = f.lower()
        if not low.endswith(PRESET_EXTENSIONS):
            continue
        meta = {}
        meta_path = os.path.join(d, os.path.splitext(f)[0] + ".meta")
        if os.path.isfile(meta_path):
            try:
                with open(meta_path, "r", encoding="utf-8") as mf:
                    meta = json.load(mf)
            except Exception:
                meta = {}
        try:
            size = os.path.getsize(os.path.join(d, f))
        except Exception:
            size = 0
        items.append({
            "id": f,
            "name": meta.get("original_name", f),
            "plugin_hint": meta.get("plugin_hint", ""),
            "size_bytes": size,
            "created_at": meta.get("created_at", ""),
        })
    return {"success": True, "presets": items}


@router.post("/upload")
async def upload_preset(
    file: UploadFile = File(...),
    plugin_hint: Optional[str] = None,
    current_user: dict = Depends(get_current_user),
):
    """Upload preset (.vstpreset / .fxp / .fxb / .dspreset) vào thư viện."""
    enforce_password_changed(current_user)
    filename = (file.filename or "preset.vstpreset").replace("\\", "/").split("/")[-1]
    ext = os.path.splitext(filename)[1].lower()
    if ext not in PRESET_EXTENSIONS:
        raise HTTPException(
            status_code=400,
            detail=f"Định dạng preset không hỗ trợ: {ext or '(không có đuôi)'} — hỗ trợ: {', '.join(PRESET_EXTENSIONS)}",
        )
    contents = await file.read()
    if not contents:
        raise HTTPException(status_code=400, detail="File rỗng")
    d = preset_library_dir()
    preset_id = uuid.uuid4().hex + ext
    dest = os.path.join(d, preset_id)
    try:
        with open(dest, "wb") as fh:
            fh.write(contents)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Không lưu được preset: {e}")
    meta = {
        "original_name": filename,
        "plugin_hint": plugin_hint or "",
        "size_bytes": len(contents),
        "created_at": time.strftime("%Y-%m-%d %H:%M:%S"),
    }
    try:
        with open(os.path.join(d, os.path.splitext(preset_id)[0] + ".meta"), "w", encoding="utf-8") as mf:
            json.dump(meta, mf, ensure_ascii=False, indent=2)
    except Exception:
        pass
    return {"success": True, "preset_id": preset_id, **meta}


@router.get("/{preset_id}/download")
async def download_preset(preset_id: str):
    path = _safe_preset_path(preset_id)
    if not path:
        raise HTTPException(status_code=404, detail="Preset không tồn tại")
    return FileResponse(path, filename=preset_id, media_type="application/octet-stream")


@router.delete("/{preset_id}")
async def delete_preset(preset_id: str, current_user: dict = Depends(get_current_user)):
    enforce_password_changed(current_user)
    path = _safe_preset_path(preset_id)
    if not path:
        raise HTTPException(status_code=404, detail="Preset không tồn tại")
    try:
        os.remove(path)
        mp = os.path.join(preset_library_dir(), os.path.splitext(preset_id)[0] + ".meta")
        if os.path.isfile(mp):
            os.remove(mp)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Không xóa được preset: {e}")
    return {"success": True, "preset_id": preset_id}
