import os, uuid, json, tempfile
from fastapi import APIRouter, HTTPException, Depends, UploadFile, File
from pydantic import BaseModel
from typing import Optional, Any
from app.config import settings
from app.core.vst_engine import PluginManager, HAS_PEDALBOARD, HAS_PYFLUIDSYNTH
from app.core.render_engine import PythonRenderEngine
from app.api.v1.auth import get_current_user

router = APIRouter()

UPLOAD_SF_DIR = os.path.join(settings.STORAGE_DIR, "soundfonts")
os.makedirs(UPLOAD_SF_DIR, exist_ok=True)


@router.get("/available")
async def list_plugins(current_user: dict = Depends(get_current_user)):
    pm = PluginManager(upload_sf_dir=UPLOAD_SF_DIR)
    return pm.list_available()


@router.get("/default-soundfonts")
async def list_default_soundfonts():
    static_sf_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "static", "soundfonts")
    result = []
    if os.path.isdir(static_sf_dir):
        for f in os.listdir(static_sf_dir):
            if f.endswith(".sf2") or f.endswith(".sf3"):
                result.append({
                    "id": os.path.splitext(f)[0],
                    "name": f,
                    "file": f,
                    "url": f"/soundfonts/{f}"
                })
    return result


@router.get("/soundfont-instruments/{sf_id}")
async def list_soundfont_instruments(sf_id: str, current_user: dict = Depends(get_current_user)):
    pm = PluginManager(upload_sf_dir=UPLOAD_SF_DIR)
    presets = pm.list_soundfont_instruments(sf_id)
    return {"presets": presets, "count": len(presets)}


@router.post("/upload-soundfont")
async def upload_soundfont(
    file: UploadFile = File(...),
    current_user: dict = Depends(get_current_user)
):
    if not (file.filename and (file.filename.endswith(".sf2") or file.filename.endswith(".sf3"))):
        raise HTTPException(status_code=400, detail="Only .sf2 / .sf3 files are allowed")

    contents = await file.read()
    if not PluginManager.validate_sf2_header(contents):
        raise HTTPException(status_code=400, detail="Invalid SoundFont file: missing RIFF/sfbk header")

    file_ext = os.path.splitext(file.filename)[1]
    file_uuid = str(uuid.uuid4())
    # Store original name in a sidecar file
    base_name = os.path.splitext(file.filename)[0].replace('/', '_').replace('\\', '_')
    file_id = file_uuid + file_ext
    dest_path = os.path.join(UPLOAD_SF_DIR, file_id)
    with open(dest_path, "wb") as f:
        f.write(contents)
    
    # Save metadata with original name
    meta_path = os.path.join(UPLOAD_SF_DIR, file_uuid + ".meta")
    with open(meta_path, "w", encoding="utf-8") as f:
        import json
        json.dump({"original_name": file.filename, "uuid": file_uuid, "file": file_id}, f)

    return {"id": file_id, "name": file.filename, "path": dest_path, "size_bytes": len(contents)}


@router.delete("/soundfont/{sf_id}")
async def delete_soundfont(sf_id: str, current_user: dict = Depends(get_current_user)):
    base_id = sf_id.replace("sf_", "")
    deleted = False
    for d in [UPLOAD_SF_DIR, os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "static", "soundfonts")]:
        if not os.path.isdir(d):
            continue
        for f in os.listdir(d):
            if os.path.splitext(f)[0] == base_id:
                path = os.path.join(d, f)
                os.remove(path)
                # Remove associated .meta file
                meta_path = os.path.join(d, os.path.splitext(f)[0] + ".meta")
                if os.path.isfile(meta_path):
                    os.remove(meta_path)
                deleted = True
                break
        if deleted:
            break
    if not deleted:
        raise HTTPException(status_code=404, detail="SoundFont not found")
    return {"deleted": True, "sf_id": sf_id}


class RenderRequest(BaseModel):
    project_json: dict
    output_filename: Optional[str] = "render_output.wav"


@router.post("/render")
async def render_project(
    req: RenderRequest,
    current_user: dict = Depends(get_current_user)
):
    engine = PythonRenderEngine()
    output_path = os.path.join(settings.PROCESSED_DIR, req.output_filename or "render_output.wav")
    try:
        result_path = engine.render_project(req.project_json, output_path)
        return {"url": f"/static/audio/processed/{os.path.basename(result_path)}", "path": result_path}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Render failed: {str(e)}")
