"""
Cache and media routes for L1 server.

Handles content retrieval, metadata, media preview, and publishing.
"""

import logging
from pathlib import Path
from typing import Optional, Dict, Any

from fastapi import APIRouter, Request, Depends, HTTPException, UploadFile, File, Form
from fastapi.responses import HTMLResponse, FileResponse
from pydantic import BaseModel

from artdag_common import render
from artdag_common.middleware import wants_html, wants_json
from artdag_common.middleware.auth import UserContext

from ..dependencies import (
    require_auth, get_templates, get_redis_client,
    get_cache_manager, get_current_user
)
from ..services.auth_service import AuthService
from ..services.cache_service import CacheService

router = APIRouter()
logger = logging.getLogger(__name__)


class UpdateMetadataRequest(BaseModel):
    title: Optional[str] = None
    description: Optional[str] = None
    tags: Optional[list] = None
    custom: Optional[Dict[str, Any]] = None


def get_cache_service():
    """Get cache service instance."""
    import database
    return CacheService(database, get_cache_manager())


@router.get("/{cid}")
async def get_cached(
    cid: str,
    request: Request,
    cache_service: CacheService = Depends(get_cache_service),
):
    """Get cached content by hash. Content negotiation: HTML for browsers, JSON for APIs."""
    ctx = await get_current_user(request)

    # Pass actor_id to get friendly name and user-specific metadata
    actor_id = ctx.actor_id if ctx else None
    cache_item = await cache_service.get_cache_item(cid, actor_id=actor_id)
    if not cache_item:
        if wants_html(request):
            templates = get_templates(request)
            return render(templates, "cache/not_found.html", request,
                cid=cid,
                user=ctx,
                active_tab="media",
            )
        raise HTTPException(404, f"Content {cid} not in cache")

    # JSON response
    if wants_json(request):
        return cache_item

    # HTML response
    if not ctx:
        from fastapi.responses import RedirectResponse
        return RedirectResponse(url="/auth", status_code=302)

    # Check access
    has_access = await cache_service.check_access(cid, ctx.actor_id, ctx.username)
    if not has_access:
        raise HTTPException(403, "Access denied")

    from ..dependencies import get_nav_counts
    nav_counts = await get_nav_counts(ctx.actor_id)

    templates = get_templates(request)
    return render(templates, "cache/detail.html", request,
        cache=cache_item,
        user=ctx,
        nav_counts=nav_counts,
        active_tab="media",
    )


@router.get("/{cid}/raw")
async def get_cached_raw(
    cid: str,
    cache_service: CacheService = Depends(get_cache_service),
):
    """Get raw cached content (file download)."""
    file_path, media_type, filename = await cache_service.get_raw_file(cid)

    if not file_path:
        raise HTTPException(404, f"Content {cid} not in cache")

    return FileResponse(file_path, media_type=media_type, filename=filename)


@router.get("/{cid}/mp4")
async def get_cached_mp4(
    cid: str,
    cache_service: CacheService = Depends(get_cache_service),
):
    """Get cached content as MP4 (transcodes MKV on first request)."""
    mp4_path, error = await cache_service.get_as_mp4(cid)

    if error:
        raise HTTPException(400 if "not a video" in error else 404, error)

    return FileResponse(mp4_path, media_type="video/mp4")


@router.get("/{cid}/meta")
async def get_metadata(
    cid: str,
    ctx: UserContext = Depends(require_auth),
    cache_service: CacheService = Depends(get_cache_service),
):
    """Get content metadata."""
    meta = await cache_service.get_metadata(cid, ctx.actor_id)
    if meta is None:
        raise HTTPException(404, "Content not found")
    return meta


@router.patch("/{cid}/meta")
async def update_metadata(
    cid: str,
    req: UpdateMetadataRequest,
    ctx: UserContext = Depends(require_auth),
    cache_service: CacheService = Depends(get_cache_service),
):
    """Update content metadata."""
    success, error = await cache_service.update_metadata(
        cid=cid,
        actor_id=ctx.actor_id,
        title=req.title,
        description=req.description,
        tags=req.tags,
        custom=req.custom,
    )

    if error:
        raise HTTPException(400, error)

    return {"updated": True}


@router.post("/{cid}/publish")
async def publish_content(
    cid: str,
    request: Request,
    ctx: UserContext = Depends(require_auth),
    cache_service: CacheService = Depends(get_cache_service),
):
    """Publish content to L2 and IPFS."""
    ipfs_cid, error = await cache_service.publish_to_l2(
        cid=cid,
        actor_id=ctx.actor_id,
        l2_server=ctx.l2_server,
        auth_token=request.cookies.get("auth_token"),
    )

    if error:
        if wants_html(request):
            return HTMLResponse(f'<span class="text-red-400">{error}</span>')
        raise HTTPException(400, error)

    if wants_html(request):
        return HTMLResponse(f'<span class="text-green-400">Published: {ipfs_cid[:16]}...</span>')

    return {"ipfs_cid": ipfs_cid, "published": True}


@router.delete("/{cid}")
async def delete_content(
    cid: str,
    ctx: UserContext = Depends(require_auth),
    cache_service: CacheService = Depends(get_cache_service),
):
    """Delete content from cache."""
    success, error = await cache_service.delete_content(cid, ctx.actor_id)

    if error:
        raise HTTPException(400 if "Cannot" in error or "pinned" in error else 404, error)

    return {"deleted": True}


@router.post("/import")
async def import_from_ipfs(
    ipfs_cid: str,
    ctx: UserContext = Depends(require_auth),
    cache_service: CacheService = Depends(get_cache_service),
):
    """Import content from IPFS."""
    cid, error = await cache_service.import_from_ipfs(ipfs_cid, ctx.actor_id)

    if error:
        raise HTTPException(400, error)

    return {"cid": cid, "imported": True}


@router.post("/upload/chunk")
async def upload_chunk(
    request: Request,
    chunk: UploadFile = File(...),
    upload_id: str = Form(...),
    chunk_index: int = Form(...),
    total_chunks: int = Form(...),
    filename: str = Form(...),
    display_name: Optional[str] = Form(None),
    ctx: UserContext = Depends(require_auth),
    cache_service: CacheService = Depends(get_cache_service),
):
    """Upload a file chunk. Assembles file when all chunks received."""
    import tempfile
    import os

    # Create temp dir for this upload
    chunk_dir = Path(tempfile.gettempdir()) / "uploads" / upload_id
    chunk_dir.mkdir(parents=True, exist_ok=True)

    # Save this chunk
    chunk_path = chunk_dir / f"chunk_{chunk_index:05d}"
    chunk_data = await chunk.read()
    chunk_path.write_bytes(chunk_data)

    # Check if all chunks received
    received = len(list(chunk_dir.glob("chunk_*")))

    if received < total_chunks:
        return {"status": "partial", "received": received, "total": total_chunks}

    # All chunks received - assemble file
    final_path = chunk_dir / filename
    with open(final_path, 'wb') as f:
        for i in range(total_chunks):
            cp = chunk_dir / f"chunk_{i:05d}"
            f.write(cp.read_bytes())
            cp.unlink()  # Clean up chunk

    # Read assembled file
    content = final_path.read_bytes()
    final_path.unlink()
    chunk_dir.rmdir()

    # Now do the normal upload flow
    cid, ipfs_cid, error = await cache_service.upload_content(
        content=content,
        filename=filename,
        actor_id=ctx.actor_id,
    )

    if error:
        raise HTTPException(400, error)

    # Assign friendly name
    final_cid = ipfs_cid or cid
    from ..services.naming_service import get_naming_service
    naming = get_naming_service()
    friendly_entry = await naming.assign_name(
        cid=final_cid,
        actor_id=ctx.actor_id,
        item_type="media",
        display_name=display_name,
        filename=filename,
    )

    return {
        "status": "complete",
        "cid": final_cid,
        "friendly_name": friendly_entry["friendly_name"],
        "filename": filename,
        "size": len(content),
        "uploaded": True,
    }


@router.post("/upload")
async def upload_content(
    file: UploadFile = File(...),
    display_name: Optional[str] = Form(None),
    ctx: UserContext = Depends(require_auth),
    cache_service: CacheService = Depends(get_cache_service),
):
    """Upload content to cache and IPFS.

    Args:
        file: The file to upload
        display_name: Optional custom name for the media (used as friendly name)
    """
    content = await file.read()
    cid, ipfs_cid, error = await cache_service.upload_content(
        content=content,
        filename=file.filename,
        actor_id=ctx.actor_id,
    )

    if error:
        raise HTTPException(400, error)

    # Assign friendly name (use IPFS CID if available, otherwise local hash)
    final_cid = ipfs_cid or cid
    from ..services.naming_service import get_naming_service
    naming = get_naming_service()
    friendly_entry = await naming.assign_name(
        cid=final_cid,
        actor_id=ctx.actor_id,
        item_type="media",
        display_name=display_name,  # Use custom name if provided
        filename=file.filename,
    )

    return {
        "cid": final_cid,
        "content_hash": cid,  # Legacy, for backwards compatibility
        "friendly_name": friendly_entry["friendly_name"],
        "filename": file.filename,
        "size": len(content),
        "uploaded": True,
    }


# Media listing endpoint
@router.get("")
async def list_media(
    request: Request,
    offset: int = 0,
    limit: int = 24,
    media_type: Optional[str] = None,
    cache_service: CacheService = Depends(get_cache_service),
    ctx: UserContext = Depends(require_auth),
):
    """List all media in cache."""
    items = await cache_service.list_media(
        actor_id=ctx.actor_id,
        username=ctx.username,
        offset=offset,
        limit=limit,
        media_type=media_type,
    )
    has_more = len(items) >= limit

    if wants_json(request):
        return {"items": items, "offset": offset, "limit": limit, "has_more": has_more}

    from ..dependencies import get_nav_counts
    nav_counts = await get_nav_counts(ctx.actor_id)

    templates = get_templates(request)
    return render(templates, "cache/media_list.html", request,
        items=items,
        user=ctx,
        nav_counts=nav_counts,
        offset=offset,
        limit=limit,
        has_more=has_more,
        active_tab="media",
    )


# HTMX metadata form
@router.get("/{cid}/meta-form", response_class=HTMLResponse)
async def get_metadata_form(
    cid: str,
    request: Request,
    cache_service: CacheService = Depends(get_cache_service),
):
    """Get metadata editing form (HTMX)."""
    ctx = await get_current_user(request)
    if not ctx:
        return HTMLResponse('<div class="text-red-400">Login required</div>')

    meta = await cache_service.get_metadata(cid, ctx.actor_id)

    return HTMLResponse(f'''
        <h2 class="text-lg font-semibold mb-4">Metadata</h2>
        <form hx-patch="/cache/{cid}/meta"
              hx-target="#metadata-section"
              hx-swap="innerHTML"
              class="space-y-4">
            <div>
                <label class="block text-gray-400 text-sm mb-1">Title</label>
                <input type="text" name="title" value="{meta.get('title', '') if meta else ''}"
                       class="w-full bg-gray-900 border border-gray-600 rounded px-3 py-2 text-white">
            </div>
            <div>
                <label class="block text-gray-400 text-sm mb-1">Description</label>
                <textarea name="description" rows="3"
                          class="w-full bg-gray-900 border border-gray-600 rounded px-3 py-2 text-white"
                >{meta.get('description', '') if meta else ''}</textarea>
            </div>
            <button type="submit"
                    class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded font-medium">
                Save Metadata
            </button>
        </form>
    ''')


@router.patch("/{cid}/meta", response_class=HTMLResponse)
async def update_metadata_htmx(
    cid: str,
    request: Request,
    cache_service: CacheService = Depends(get_cache_service),
):
    """Update metadata (HTMX form handler)."""
    ctx = await get_current_user(request)
    if not ctx:
        return HTMLResponse('<div class="text-red-400">Login required</div>')

    form_data = await request.form()

    success, error = await cache_service.update_metadata(
        cid=cid,
        actor_id=ctx.actor_id,
        title=form_data.get("title"),
        description=form_data.get("description"),
    )

    if error:
        return HTMLResponse(f'<div class="text-red-400">{error}</div>')

    return HTMLResponse('''
        <div class="text-green-400 mb-4">Metadata saved!</div>
        <script>setTimeout(() => location.reload(), 1000);</script>
    ''')


# Friendly name editing
@router.get("/{cid}/name-form", response_class=HTMLResponse)
async def get_name_form(
    cid: str,
    request: Request,
    cache_service: CacheService = Depends(get_cache_service),
):
    """Get friendly name editing form (HTMX)."""
    ctx = await get_current_user(request)
    if not ctx:
        return HTMLResponse('<div class="text-red-400">Login required</div>')

    # Get current friendly name
    from ..services.naming_service import get_naming_service
    naming = get_naming_service()
    entry = await naming.get_by_cid(ctx.actor_id, cid)
    current_name = entry.get("base_name", "") if entry else ""

    return HTMLResponse(f'''
        <form hx-post="/cache/{cid}/name"
              hx-target="#friendly-name-section"
              hx-swap="innerHTML"
              class="space-y-3">
            <div>
                <label class="block text-gray-400 text-sm mb-1">Friendly Name</label>
                <input type="text" name="display_name" value="{current_name}"
                       placeholder="e.g., my-background-video"
                       class="w-full bg-gray-900 border border-gray-600 rounded px-3 py-2 text-white">
                <p class="text-gray-500 text-xs mt-1">A name to reference this media in recipes</p>
            </div>
            <div class="flex space-x-2">
                <button type="submit"
                        class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded font-medium">
                    Save
                </button>
                <button type="button"
                        onclick="location.reload()"
                        class="px-4 py-2 rounded border border-gray-600 hover:bg-gray-700">
                    Cancel
                </button>
            </div>
        </form>
    ''')


@router.post("/{cid}/name", response_class=HTMLResponse)
async def update_friendly_name(
    cid: str,
    request: Request,
):
    """Update friendly name (HTMX form handler)."""
    ctx = await get_current_user(request)
    if not ctx:
        return HTMLResponse('<div class="text-red-400">Login required</div>')

    form_data = await request.form()
    display_name = form_data.get("display_name", "").strip()

    if not display_name:
        return HTMLResponse('<div class="text-red-400">Name cannot be empty</div>')

    from ..services.naming_service import get_naming_service
    naming = get_naming_service()

    try:
        entry = await naming.assign_name(
            cid=cid,
            actor_id=ctx.actor_id,
            item_type="media",
            display_name=display_name,
        )

        return HTMLResponse(f'''
            <div class="text-green-400 mb-2">Name updated!</div>
            <script>setTimeout(() => location.reload(), 1000);</script>
        ''')
    except Exception as e:
        return HTMLResponse(f'<div class="text-red-400">Error: {e}</div>')
