"""Transcription API routes."""

import uuid
import shutil
from pathlib import Path
from threading import Thread, Lock
from collections import deque
from typing import List
from fastapi import APIRouter, HTTPException, UploadFile, File
from fastapi.responses import PlainTextResponse, Response

from ..models import (
    TranscribeRequest,
    TranscribeResponse,
    StatusResponse,
    ResultResponse,
    JobStatus,
    VideoPreviewRequest,
    VideoPreview,
    QueueRequest,
    QueueStatusResponse,
    HistoryResponse,
    HistoryItem,
    ExportFormat,
    UploadResponse,
    PlaylistPreview,
    PlaylistVideo,
    PlaylistRequest,
    QARequest,
    QAResponse,
    CustomPromptAnalysisRequest,
    BookReferencesRequest,
)
from ..config import get_api_key, get_output_directory, get_temp_dir
from ..services.downloader import download_audio, get_video_info, get_playlist_info
from ..services.transcriber import transcribe_audio, cleanup_audio, text_to_srt, text_to_vtt
from ..services.pdf_exporter import create_pdf
from ..services.markdown_exporter import create_markdown
from ..services.history import (
    add_to_history, get_history, get_history_item,
    delete_history_item, get_transcription_text, clear_history,
    update_history_item, add_cost_entry, add_qa_entry, save_resources,
    get_item_costs, get_full_item
)
from ..services.analyzer import (
    analyze_transcription, translate_text, format_transcription,
    analyze_with_custom_prompt, answer_question
)
from ..services.research import comprehensive_qa as research_qa, find_book_references
from ..services.multi_provider import (
    comprehensive_qa as multi_provider_qa,
    analyze_with_provider,
    critique_with_provider,
    find_resources_with_provider
)
from ..services.webhook import send_webhook_sync, create_transcription_complete_payload, create_transcription_error_payload
from ..config import get_custom_prompts, load_config, get_webhook_config
from ..services.topics import (
    add_topics_to_video, remove_topic_from_video, get_video_topics,
    get_all_topics, search_topics, get_videos_by_topic, get_related_videos,
    delete_video_topics
)
from ..services.language import detect_language_from_text

router = APIRouter()

# In-memory job storage
jobs = {}
jobs_lock = Lock()

# Cancelled jobs set
cancelled_jobs = set()
cancelled_lock = Lock()

# Queue for batch processing
job_queue = deque()
queue_lock = Lock()
queue_processing = False


def is_cancelled(job_id: str) -> bool:
    """Check if a job has been cancelled."""
    with cancelled_lock:
        return job_id in cancelled_jobs


def save_transcription(title: str, text: str) -> str:
    """Save transcription to output directory and return file path."""
    output_dir = get_output_directory()
    safe_title = "".join(c for c in title if c.isalnum() or c in (' ', '-', '_')).strip()
    safe_title = safe_title[:100] if len(safe_title) > 100 else safe_title
    if not safe_title:
        safe_title = "transcription"
    file_path = output_dir / f"{safe_title}.txt"

    counter = 1
    while file_path.exists():
        file_path = output_dir / f"{safe_title}_{counter}.txt"
        counter += 1

    with open(file_path, 'w', encoding='utf-8') as f:
        f.write(f"Title: {title}\n")
        f.write("=" * 50 + "\n\n")
        f.write(text)

    return str(file_path)


def update_job(job_id: str, **kwargs):
    """Thread-safe job update."""
    with jobs_lock:
        if job_id in jobs:
            jobs[job_id].update(kwargs)


def process_job(job_id: str, url: str):
    """Background task to download and transcribe video."""
    file_path = None
    try:
        api_key = get_api_key()
        if not api_key:
            raise Exception("OpenAI API key not configured")

        # Check cancellation
        if is_cancelled(job_id):
            update_job(job_id, status=JobStatus.ERROR, message="Cancelled", stage="Cancelled")
            return

        # Fetching info
        update_job(job_id, status=JobStatus.FETCHING_INFO, progress=5, stage="Fetching video info...")

        # Download progress callback
        def download_progress(percent, message):
            if is_cancelled(job_id):
                raise Exception("Cancelled")
            total_progress = 5 + int(percent * 0.35)
            update_job(job_id, progress=total_progress, stage=message)

        # Check cancellation
        if is_cancelled(job_id):
            update_job(job_id, status=JobStatus.ERROR, message="Cancelled", stage="Cancelled")
            return

        # Download audio
        update_job(job_id, status=JobStatus.DOWNLOADING, progress=10, stage="Starting download...")
        temp_dir = get_temp_dir()
        file_path, title, video_info = download_audio(url, str(temp_dir), download_progress)
        update_job(job_id, title=title, video_info=video_info, progress=40, stage="Download complete")

        # Check cancellation
        if is_cancelled(job_id):
            if file_path:
                cleanup_audio(file_path)
            update_job(job_id, status=JobStatus.ERROR, message="Cancelled", stage="Cancelled")
            return

        # Converting
        update_job(job_id, status=JobStatus.CONVERTING, progress=42, stage="Converting audio...")

        # Transcribe progress callback
        def transcribe_progress(percent, message):
            if is_cancelled(job_id):
                raise Exception("Cancelled")
            total_progress = 45 + int(percent * 0.45)
            update_job(job_id, progress=total_progress, stage=message)

        # Check cancellation
        if is_cancelled(job_id):
            if file_path:
                cleanup_audio(file_path)
            update_job(job_id, status=JobStatus.ERROR, message="Cancelled", stage="Cancelled")
            return

        # Transcribe
        update_job(job_id, status=JobStatus.TRANSCRIBING, progress=45, stage="Starting transcription...")
        text = transcribe_audio(file_path, api_key, transcribe_progress)

        # Check cancellation
        if is_cancelled(job_id):
            if file_path:
                cleanup_audio(file_path)
            update_job(job_id, status=JobStatus.ERROR, message="Cancelled", stage="Cancelled")
            return

        # Saving
        update_job(job_id, status=JobStatus.SAVING, progress=92, stage="Saving transcription...")
        saved_path = save_transcription(title, text)

        # Detect language and text direction
        language, text_direction = detect_language_from_text(text)

        # Add to history
        add_to_history(
            id=job_id,
            title=title,
            url=url,
            file_path=saved_path,
            duration=video_info.get('duration'),
            thumbnail=video_info.get('thumbnail'),
            language=language,
            text_direction=text_direction
        )

        # Cleanup
        cleanup_audio(file_path)

        # Complete
        update_job(
            job_id,
            status=JobStatus.COMPLETE,
            progress=100,
            stage="Complete!",
            text=text,
            file_path=saved_path,
            language=language,
            text_direction=text_direction
        )

        # Send webhook notification if configured
        webhook_url, webhook_enabled = get_webhook_config()
        if webhook_enabled and webhook_url:
            try:
                payload = create_transcription_complete_payload(
                    job_id=job_id,
                    title=title,
                    url=url,
                    text=text,
                    duration=video_info.get('duration'),
                    thumbnail=video_info.get('thumbnail')
                )
                send_webhook_sync(webhook_url, payload)
            except Exception as webhook_error:
                print(f"Webhook failed: {webhook_error}")

    except Exception as e:
        error_msg = str(e)
        if error_msg == "Cancelled":
            update_job(job_id, status=JobStatus.ERROR, message="Cancelled", stage="Cancelled")
        else:
            update_job(job_id, status=JobStatus.ERROR, message=error_msg, stage="Error")
            # Send error webhook if configured
            webhook_url, webhook_enabled = get_webhook_config()
            if webhook_enabled and webhook_url:
                try:
                    payload = create_transcription_error_payload(
                        job_id=job_id,
                        url=url,
                        error=error_msg
                    )
                    send_webhook_sync(webhook_url, payload)
                except Exception:  # pragma: no cover
                    pass  # Webhook failure shouldn't break error handling
        # Cleanup on error
        if file_path:
            try:
                cleanup_audio(file_path)
            except:  # pragma: no cover
                pass  # Best effort cleanup

    # Clean up cancelled status
    with cancelled_lock:
        cancelled_jobs.discard(job_id)

    # Process next in queue
    process_queue()


def process_queue():
    """Process the next item in the queue."""
    global queue_processing

    with queue_lock:
        if not job_queue:
            queue_processing = False
            return

        if queue_processing:
            return

        queue_processing = True
        job_id, url = job_queue.popleft()

    thread = Thread(target=process_job, args=(job_id, url))
    thread.start()


# Allowed audio file extensions and max size
ALLOWED_AUDIO_EXTENSIONS = {'.mp3', '.wav', '.m4a', '.flac', '.ogg', '.webm', '.mp4'}
MAX_UPLOAD_SIZE = 25 * 1024 * 1024  # 25MB


def process_upload_job(job_id: str, file_path: str, filename: str):
    """Background task to transcribe an uploaded audio file."""
    try:
        api_key = get_api_key()
        if not api_key:
            raise Exception("OpenAI API key not configured")

        # Check cancellation
        if is_cancelled(job_id):
            update_job(job_id, status=JobStatus.ERROR, message="Cancelled", stage="Cancelled")
            cleanup_audio(file_path)
            return

        # Use filename (without extension) as title
        title = Path(filename).stem

        # Update job with title
        update_job(job_id, title=title, progress=10, stage="Processing uploaded file...")

        # Check cancellation
        if is_cancelled(job_id):
            update_job(job_id, status=JobStatus.ERROR, message="Cancelled", stage="Cancelled")
            cleanup_audio(file_path)
            return

        # Transcribe progress callback
        def transcribe_progress(percent, message):
            if is_cancelled(job_id):
                raise Exception("Cancelled")
            total_progress = 10 + int(percent * 0.80)
            update_job(job_id, progress=total_progress, stage=message)

        # Transcribe
        update_job(job_id, status=JobStatus.TRANSCRIBING, progress=15, stage="Starting transcription...")
        text = transcribe_audio(file_path, api_key, transcribe_progress)

        # Check cancellation
        if is_cancelled(job_id):
            cleanup_audio(file_path)
            update_job(job_id, status=JobStatus.ERROR, message="Cancelled", stage="Cancelled")
            return

        # Saving
        update_job(job_id, status=JobStatus.SAVING, progress=92, stage="Saving transcription...")
        saved_path = save_transcription(title, text)

        # Add to history (no URL for uploaded files)
        add_to_history(
            id=job_id,
            title=title,
            url=f"file://{filename}",
            file_path=saved_path,
            duration=None,
            thumbnail=None
        )

        # Cleanup uploaded file
        cleanup_audio(file_path)

        # Complete
        update_job(
            job_id,
            status=JobStatus.COMPLETE,
            progress=100,
            stage="Complete!",
            text=text,
            file_path=saved_path
        )

        # Send webhook notification if configured
        webhook_url, webhook_enabled = get_webhook_config()
        if webhook_enabled and webhook_url:
            try:
                payload = create_transcription_complete_payload(
                    job_id=job_id,
                    title=title,
                    url=f"file://{filename}",
                    text=text,
                    duration=None,
                    thumbnail=None
                )
                send_webhook_sync(webhook_url, payload)
            except Exception as webhook_error:
                print(f"Webhook failed: {webhook_error}")

    except Exception as e:
        error_msg = str(e)
        if error_msg == "Cancelled":
            update_job(job_id, status=JobStatus.ERROR, message="Cancelled", stage="Cancelled")
        else:
            update_job(job_id, status=JobStatus.ERROR, message=error_msg, stage="Error")
            # Send error webhook if configured
            webhook_url, webhook_enabled = get_webhook_config()
            if webhook_enabled and webhook_url:
                try:
                    payload = create_transcription_error_payload(
                        job_id=job_id,
                        url=f"file://{filename}",
                        error=error_msg
                    )
                    send_webhook_sync(webhook_url, payload)
                except Exception:  # pragma: no cover
                    pass  # Webhook failure shouldn't break error handling
        # Cleanup on error
        try:
            cleanup_audio(file_path)
        except:  # pragma: no cover
            pass  # Best effort cleanup

    # Clean up cancelled status
    with cancelled_lock:
        cancelled_jobs.discard(job_id)


# Video Preview
@router.post("/preview", response_model=VideoPreview)
async def preview_video(request: VideoPreviewRequest):
    """Fetch video metadata without downloading."""
    try:
        info = get_video_info(request.url)
        return VideoPreview(
            url=request.url,
            video_id=info['video_id'],
            title=info['title'],
            thumbnail=info['thumbnail'],
            duration=info['duration'],
            channel=info['channel']
        )
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))


# Playlist Preview
@router.post("/preview/playlist", response_model=PlaylistPreview)
async def preview_playlist(request: PlaylistRequest):
    """Fetch playlist metadata without downloading."""
    try:
        info = get_playlist_info(request.url)
        return PlaylistPreview(
            playlist_id=info['playlist_id'],
            title=info['title'],
            channel=info['channel'],
            video_count=info['video_count'],
            videos=[PlaylistVideo(**v) for v in info['videos']]
        )
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))


# Transcription
@router.post("/transcribe", response_model=TranscribeResponse)
async def create_transcription(request: TranscribeRequest):
    """Start a new transcription job."""
    api_key = get_api_key()
    if not api_key:
        raise HTTPException(
            status_code=400,
            detail="OpenAI API key not configured. Please set it in Settings."
        )

    job_id = str(uuid.uuid4())
    with jobs_lock:
        jobs[job_id] = {
            "status": JobStatus.PENDING,
            "progress": 0,
            "stage": "Queued",
            "title": "",
            "text": "",
            "message": None,
            "file_path": None,
            "video_info": None,
        }

    thread = Thread(target=process_job, args=(job_id, request.url))
    thread.start()

    return TranscribeResponse(job_id=job_id, status=JobStatus.PENDING)


# Upload Audio File
@router.post("/transcribe/upload", response_model=UploadResponse)
async def upload_transcription(file: UploadFile = File(...)):
    """
    Upload an audio file for transcription.

    Supported formats: MP3, WAV, M4A, FLAC, OGG, WebM, MP4
    Max file size: 25MB
    """
    api_key = get_api_key()
    if not api_key:
        raise HTTPException(
            status_code=400,
            detail="OpenAI API key not configured. Please set it in Settings."
        )

    # Validate file extension
    filename = file.filename or "audio"
    file_ext = Path(filename).suffix.lower()
    if file_ext not in ALLOWED_AUDIO_EXTENSIONS:
        raise HTTPException(
            status_code=400,
            detail=f"Unsupported file format. Allowed: {', '.join(ALLOWED_AUDIO_EXTENSIONS)}"
        )

    # Save uploaded file to temp directory
    temp_dir = get_temp_dir()
    job_id = str(uuid.uuid4())
    temp_file_path = temp_dir / f"{job_id}{file_ext}"

    try:
        # Read and save file
        content = await file.read()

        # Check file size
        if len(content) > MAX_UPLOAD_SIZE:
            raise HTTPException(
                status_code=400,
                detail=f"File too large. Maximum size is {MAX_UPLOAD_SIZE // (1024*1024)}MB"
            )

        with open(temp_file_path, 'wb') as f:
            f.write(content)

    except HTTPException:
        raise
    except Exception as e:  # pragma: no cover
        raise HTTPException(status_code=500, detail=f"Failed to save uploaded file: {str(e)}")

    # Create job
    with jobs_lock:
        jobs[job_id] = {
            "status": JobStatus.PENDING,
            "progress": 0,
            "stage": "Processing upload...",
            "title": Path(filename).stem,
            "text": "",
            "message": None,
            "file_path": None,
            "video_info": None,
        }

    # Start transcription in background
    thread = Thread(target=process_upload_job, args=(job_id, str(temp_file_path), filename))
    thread.start()

    return UploadResponse(job_id=job_id, status=JobStatus.PENDING, filename=filename)


# Queue/Batch
@router.post("/queue", response_model=QueueStatusResponse)
async def add_to_queue(request: QueueRequest):
    """Add multiple URLs to the transcription queue."""
    api_key = get_api_key()
    if not api_key:
        raise HTTPException(status_code=400, detail="OpenAI API key not configured")

    job_ids = []
    with queue_lock:
        for url in request.urls:
            job_id = str(uuid.uuid4())
            with jobs_lock:
                jobs[job_id] = {
                    "status": JobStatus.PENDING,
                    "progress": 0,
                    "stage": "Queued",
                    "title": "",
                    "text": "",
                    "message": None,
                    "file_path": None,
                    "video_info": None,
                    "url": url,
                }
            job_queue.append((job_id, url))
            job_ids.append({"job_id": job_id, "url": url})

    # Start processing if not already
    process_queue()

    return QueueStatusResponse(
        queue=job_ids,
        current_job=job_ids[0]["job_id"] if job_ids else None,
        total=len(job_ids),
        completed=0
    )


@router.get("/queue", response_model=QueueStatusResponse)
async def get_queue_status():
    """Get current queue status."""
    with queue_lock:
        queue_list = [{"job_id": jid, "url": url} for jid, url in job_queue]

    with jobs_lock:
        current = None
        completed = 0
        for jid, job in jobs.items():
            if job["status"] == JobStatus.COMPLETE:
                completed += 1
            elif job["status"] not in (JobStatus.PENDING, JobStatus.ERROR, JobStatus.COMPLETE):
                current = jid

    return QueueStatusResponse(
        queue=queue_list,
        current_job=current,
        total=len(queue_list),
        completed=completed
    )


# Status
@router.get("/status/{job_id}", response_model=StatusResponse)
async def get_status(job_id: str):
    """Get the status of a transcription job."""
    with jobs_lock:
        if job_id not in jobs:
            raise HTTPException(status_code=404, detail="Job not found")
        job = jobs[job_id].copy()

    return StatusResponse(
        status=job["status"],
        progress=job["progress"],
        message=job.get("message"),
        stage=job.get("stage")
    )


# Cancel
@router.post("/cancel/{job_id}")
async def cancel_job(job_id: str):
    """Cancel a running transcription job."""
    with jobs_lock:
        if job_id not in jobs:
            raise HTTPException(status_code=404, detail="Job not found")
        job = jobs[job_id]
        if job["status"] in (JobStatus.COMPLETE, JobStatus.ERROR):
            raise HTTPException(status_code=400, detail="Job already finished")

    # Mark as cancelled
    with cancelled_lock:
        cancelled_jobs.add(job_id)

    # Update job status immediately for UI feedback
    update_job(job_id, stage="Cancelling...")

    return {"success": True, "message": "Cancellation requested"}


# Result
@router.get("/result/{job_id}", response_model=ResultResponse)
async def get_result(job_id: str):
    """Get the result of a completed transcription job."""
    with jobs_lock:
        if job_id not in jobs:
            raise HTTPException(status_code=404, detail="Job not found")
        job = jobs[job_id].copy()

    if job["status"] != JobStatus.COMPLETE:
        raise HTTPException(status_code=400, detail="Job not complete")

    return ResultResponse(
        text=job["text"],
        title=job["title"],
        file_path=job.get("file_path"),
        language=job.get("language"),
        text_direction=job.get("text_direction", "ltr")
    )


# History
@router.get("/history", response_model=HistoryResponse)
async def get_history_list(search: str = "", limit: int = 50, offset: int = 0):
    """Get transcription history."""
    items, total = get_history(search=search or None, limit=limit, offset=offset)
    return HistoryResponse(
        items=[HistoryItem(**item) for item in items],
        total=total
    )


@router.get("/history/{item_id}")
async def get_history_detail(item_id: str):
    """Get a specific history item with full text."""
    item = get_history_item(item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    text = get_transcription_text(item['file_path'])

    # Detect language if not already set
    language = item.get('language')
    text_direction = item.get('text_direction')

    if text and not text_direction:
        detected_lang, detected_dir = detect_language_from_text(text)
        if not language:
            language = detected_lang
        text_direction = detected_dir
        # Update for future requests
        update_history_item(item_id, language=language, text_direction=text_direction)

    return {
        **item,
        "text": text,
        "language": language,
        "text_direction": text_direction or "ltr"
    }


@router.delete("/history/{item_id}")
async def delete_history(item_id: str):
    """Delete a history item."""
    if delete_history_item(item_id):
        return {"success": True}
    raise HTTPException(status_code=404, detail="Item not found")


@router.delete("/history")
async def clear_all_history():
    """Clear all history."""
    clear_history()
    return {"success": True}


# Export
@router.get("/export/{item_id}")
async def export_transcription(item_id: str, format: ExportFormat = ExportFormat.TXT):
    """Export a transcription in various formats."""
    # Check in active jobs first
    metadata = {}
    with jobs_lock:
        if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
            text = jobs[item_id]["text"]
            title = jobs[item_id]["title"]
            video_info = jobs[item_id].get("video_info", {})
            metadata = {
                "url": video_info.get("url", ""),
                "duration": video_info.get("duration", ""),
            }
        else:
            # Check history
            item = get_history_item(item_id)
            if not item:
                raise HTTPException(status_code=404, detail="Item not found")
            text = get_transcription_text(item['file_path'])
            title = item['title']
            metadata = {
                "url": item.get("url", ""),
                "duration": item.get("duration", ""),
                "created_at": item.get("created_at", ""),
            }
            if not text:
                raise HTTPException(status_code=404, detail="Transcription file not found")

    safe_title = "".join(c for c in title if c.isalnum() or c in (' ', '-', '_')).strip()[:50]

    if format == ExportFormat.TXT:
        return PlainTextResponse(
            content=text,
            headers={"Content-Disposition": f'attachment; filename="{safe_title}.txt"'}
        )
    elif format == ExportFormat.SRT:
        srt_content = text_to_srt(text, title)
        return PlainTextResponse(
            content=srt_content,
            headers={"Content-Disposition": f'attachment; filename="{safe_title}.srt"'}
        )
    elif format == ExportFormat.VTT:
        vtt_content = text_to_vtt(text, title)
        return PlainTextResponse(
            content=vtt_content,
            headers={"Content-Disposition": f'attachment; filename="{safe_title}.vtt"'}
        )
    elif format == ExportFormat.PDF:
        pdf_bytes = create_pdf(title, text, metadata)
        return Response(
            content=pdf_bytes,
            media_type="application/pdf",
            headers={"Content-Disposition": f'attachment; filename="{safe_title}.pdf"'}
        )
    elif format == ExportFormat.MD:
        md_content = create_markdown(title, text, metadata)
        return PlainTextResponse(
            content=md_content,
            media_type="text/markdown",
            headers={"Content-Disposition": f'attachment; filename="{safe_title}.md"'}
        )
    else:  # pragma: no cover
        raise HTTPException(status_code=400, detail="Unsupported format")  # ExportFormat enum prevents this


# AI Analysis
@router.post("/analyze/{item_id}")
async def analyze_content(item_id: str, analysis_type: str = "full", force: bool = False):
    """
    Analyze transcription with AI.

    analysis_type can be: "full", "summary", "takeaways", or "topics"
    Results are cached in history to avoid re-analyzing.
    Use force=True to bypass cache and re-analyze.
    """
    config = load_config()
    if not config.eden_api_key:
        raise HTTPException(status_code=400, detail="Eden.ai API key not configured. Set it in Settings.")

    # Get history item and check for cached analysis
    item = get_history_item(item_id)
    title = ""
    if item:
        title = item.get('title', '')
        # Return cached analysis if available and full analysis requested (unless force=True)
        if not force and analysis_type == "full" and item.get('analysis'):
            return item['analysis']

    # Get transcription text
    with jobs_lock:
        if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
            text = jobs[item_id]["text"]
            title = jobs[item_id].get("title", title)
        else:
            if not item:
                raise HTTPException(status_code=404, detail="Item not found")
            text = get_transcription_text(item['file_path'])
            if not text:
                raise HTTPException(status_code=404, detail="Transcription file not found")

    if not text or len(text.strip()) < 50:
        raise HTTPException(status_code=400, detail="Transcription too short to analyze")

    try:
        result = analyze_with_provider(text, analysis_type)

        # Save analysis to history and topics database
        if analysis_type == "full":
            update_history_item(item_id, analysis=result)
            # Save topics to topics database
            topics = result.get('topics') if isinstance(result, dict) else None
            if topics:
                add_topics_to_video(item_id, topics, title)

        # Track cost if available
        cost_info = result.get('cost_info') if isinstance(result, dict) else None
        if cost_info:
            add_cost_entry(item_id, cost_info)

        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}")


# Translation
@router.post("/translate/{item_id}")
async def translate_content(item_id: str, target_language: str = "English"):
    """
    Translate transcription to a target language.
    Translations are cached in history to avoid re-translating.

    Args:
        item_id: Job ID or history item ID
        target_language: Target language for translation (e.g., "English", "Spanish", "French")
    """
    api_key = get_api_key()
    if not api_key:
        raise HTTPException(status_code=400, detail="OpenAI API key not configured")

    # Check for cached translation
    item = get_history_item(item_id)
    if item:
        translations = item.get('translations', {})
        if target_language in translations:
            return {"translation": translations[target_language], "target_language": target_language, "cached": True}

    # Get transcription text
    with jobs_lock:
        if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
            text = jobs[item_id]["text"]
        else:
            if not item:
                raise HTTPException(status_code=404, detail="Item not found")
            text = get_transcription_text(item['file_path'])
            if not text:
                raise HTTPException(status_code=404, detail="Transcription file not found")

    if not text or len(text.strip()) < 10:
        raise HTTPException(status_code=400, detail="Transcription too short to translate")

    try:
        translated = translate_text(text, api_key, target_language)

        # Cache translation in history
        if item:
            translations = item.get('translations', {})
            translations[target_language] = translated
            update_history_item(item_id, translations=translations)

        return {"translation": translated, "target_language": target_language}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Translation failed: {str(e)}")


# Format with AI
@router.post("/format/{item_id}")
async def format_content(item_id: str):
    """
    Format transcription with headers and better structure.
    Organizes content under logical section headers while preserving all text.
    Results are cached in history.
    """
    api_key = get_api_key()
    if not api_key:
        raise HTTPException(status_code=400, detail="OpenAI API key not configured")

    # Check for cached formatted text
    item = get_history_item(item_id)
    if item and item.get('formatted_text'):
        return {"formatted_text": item['formatted_text'], "cached": True}

    # Get transcription text
    with jobs_lock:
        if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
            text = jobs[item_id]["text"]
        else:
            if not item:
                raise HTTPException(status_code=404, detail="Item not found")
            text = get_transcription_text(item['file_path'])
            if not text:
                raise HTTPException(status_code=404, detail="Transcription file not found")

    if not text or len(text.strip()) < 50:
        raise HTTPException(status_code=400, detail="Transcription too short to format")

    try:
        formatted = format_transcription(text, api_key)

        # Cache formatted text in history
        if item:
            update_history_item(item_id, formatted_text=formatted)

        return {"formatted_text": formatted}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Formatting failed: {str(e)}")


# Topics API
@router.get("/topics")
async def list_topics(search: str = ""):
    """Get all topics or search topics."""
    if search:
        return {"topics": search_topics(search)}
    return {"topics": get_all_topics()}


@router.get("/topics/{topic}/videos")
async def get_topic_videos(topic: str):
    """Get all videos for a specific topic."""
    video_ids = get_videos_by_topic(topic)
    # Get video details from history
    videos = []
    for vid in video_ids:
        item = get_history_item(vid)
        if item:
            videos.append({
                "id": item['id'],
                "title": item['title'],
                "thumbnail": item.get('thumbnail'),
                "created_at": item.get('created_at'),
                "duration": item.get('duration')
            })
    return {"topic": topic, "videos": videos, "count": len(videos)}


@router.get("/history/{item_id}/topics")
async def get_item_topics(item_id: str):
    """Get topics for a specific video."""
    topics = get_video_topics(item_id)
    return {"video_id": item_id, "topics": topics}


@router.post("/history/{item_id}/topics")
async def add_item_topics(item_id: str, topics: List[str]):
    """Add topics to a video (manual tagging)."""
    item = get_history_item(item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    add_topics_to_video(item_id, topics, item.get('title', ''))
    return {"success": True, "topics": get_video_topics(item_id)}


@router.delete("/history/{item_id}/topics/{topic}")
async def remove_item_topic(item_id: str, topic: str):
    """Remove a topic from a video."""
    if remove_topic_from_video(item_id, topic):
        return {"success": True}
    raise HTTPException(status_code=404, detail="Topic not found for this video")


@router.get("/history/{item_id}/related")
async def get_related_items(item_id: str, limit: int = 5):
    """Get videos related to this one based on shared topics."""
    related = get_related_videos(item_id, limit)
    # Enrich with video details
    for item in related:
        history_item = get_history_item(item['video_id'])
        if history_item:
            item['title'] = history_item.get('title', item.get('title', ''))
            item['thumbnail'] = history_item.get('thumbnail')
            item['duration'] = history_item.get('duration')
    return {"video_id": item_id, "related": related}


# Downloadable Package
@router.get("/package/{item_id}")
async def get_transcription_package(item_id: str):
    """
    Get a complete package of all transcription data including:
    - Transcription text
    - Analysis (summary, takeaways, topics)
    - Translations
    - Video metadata
    """
    item = get_history_item(item_id)
    if not item:
        # Check active jobs
        with jobs_lock:
            if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
                job = jobs[item_id]
                return {
                    "id": item_id,
                    "title": job.get("title", ""),
                    "transcription": job.get("text", ""),
                    "analysis": None,
                    "translations": {},
                    "topics": [],
                    "metadata": {
                        "video_info": job.get("video_info"),
                    }
                }
        raise HTTPException(status_code=404, detail="Item not found")

    # Get transcription text
    text = get_transcription_text(item['file_path'])

    # Get topics
    topics = get_video_topics(item_id)

    # Get related videos
    related = get_related_videos(item_id, 5)

    return {
        "id": item_id,
        "title": item.get('title', ''),
        "url": item.get('url', ''),
        "transcription": text,
        "analysis": item.get('analysis'),
        "translations": item.get('translations', {}),
        "topics": topics,
        "related_videos": related,
        "metadata": {
            "created_at": item.get('created_at'),
            "duration": item.get('duration'),
            "thumbnail": item.get('thumbnail'),
        }
    }


# Q&A on Transcription
@router.post("/qa/{item_id}", response_model=QAResponse)
async def ask_question(item_id: str, request: QARequest):
    """
    Ask a question about a transcription.

    Uses the configured analysis provider to answer,
    optionally with critique from a second provider and external references.

    Args:
        item_id: The transcription ID
        request: Contains question and whether to find references
    """
    config = load_config()

    # Check we have Eden.ai configured
    if not config.eden_api_key:
        raise HTTPException(status_code=400, detail="Eden.ai API key not configured. Set it in Settings.")

    # Get transcription text
    item = get_history_item(item_id)
    text = None

    with jobs_lock:
        if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
            text = jobs[item_id]["text"]
        elif item:
            text = get_transcription_text(item['file_path'])

    if not text:
        raise HTTPException(status_code=404, detail="Transcription not found")

    if len(text.strip()) < 50:
        raise HTTPException(status_code=400, detail="Transcription too short for Q&A")

    try:
        # Use multi-provider Q&A
        result = multi_provider_qa(
            text=text,
            question=request.question,
            find_references=request.find_references
        )

        # Format response for QAResponse model
        response = {
            "question": request.question,
            "transcription_answer": result.get("initial_answer"),
            "references": result.get("references"),
            "combined_analysis": result.get("critique"),
            "references_error": result.get("references_error")
        }

        return QAResponse(**response)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Q&A failed: {str(e)}")


# Find Book References
@router.post("/references/{item_id}")
async def get_book_references(item_id: str, request: BookReferencesRequest):
    """
    Find book and resource recommendations related to a topic from the transcription.

    Uses the configured resources provider (Perplexity or Eden.ai).

    Args:
        item_id: The transcription ID (for context)
        request: Contains the topic to find references for
    """
    config = load_config()

    # Check we have Eden.ai configured
    if not config.eden_api_key:
        raise HTTPException(status_code=400, detail="Eden.ai API key not configured. Set it in Settings.")

    # Get transcription text for context
    item = get_history_item(item_id)
    text = None

    with jobs_lock:
        if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
            text = jobs[item_id]["text"]
        elif item:
            text = get_transcription_text(item['file_path'])

    context = text[:3000] if text else None

    try:
        result = find_resources_with_provider(
            topic=request.topic,
            context=context
        )
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to find references: {str(e)}")


# Find Resources (one-click)
@router.get("/resources/{item_id}")
async def find_resources_for_item(item_id: str):
    """
    Find resources and citations for a transcription with one click.
    Automatically extracts topics and finds relevant resources.
    """
    config = load_config()

    if not config.eden_api_key:
        raise HTTPException(status_code=400, detail="Eden.ai API key not configured. Set it in Settings.")

    # Get transcription text
    item = get_history_item(item_id)
    text = None
    title = ""

    with jobs_lock:
        if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
            text = jobs[item_id]["text"]
            title = jobs[item_id].get("title", "")
        elif item:
            text = get_transcription_text(item['file_path'])
            title = item.get('title', '')

    if not text:
        raise HTTPException(status_code=404, detail="Transcription not found")

    # Use the title and first part of text as context
    topic = title if title else "the content discussed in this transcription"
    context = text[:3000]

    try:
        result = find_resources_with_provider(topic=topic, context=context)
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to find resources: {str(e)}")


# Generate Suggested Questions
@router.get("/questions/{item_id}")
async def get_suggested_questions(item_id: str):
    """
    Generate suggested questions about a transcription.
    Returns 8 insightful questions the user might want to ask.
    """
    config = load_config()

    if not config.eden_api_key:
        raise HTTPException(status_code=400, detail="Eden.ai API key not configured. Set it in Settings.")

    # Get transcription text
    item = get_history_item(item_id)
    text = None

    with jobs_lock:
        if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
            text = jobs[item_id]["text"]
        elif item:
            text = get_transcription_text(item['file_path'])

    if not text:
        raise HTTPException(status_code=404, detail="Transcription not found")

    if len(text.strip()) < 100:
        raise HTTPException(status_code=400, detail="Transcription too short to generate questions")

    try:
        from ..services.eden_ai import generate_questions
        import asyncio
        import concurrent.futures

        def run_async():
            return asyncio.run(generate_questions(text, config.eden_api_key))

        with concurrent.futures.ThreadPoolExecutor() as executor:
            future = executor.submit(run_async)
            questions = future.result(timeout=60)

        return {"questions": questions}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to generate questions: {str(e)}")


# Custom Prompt Analysis
@router.post("/analyze/{item_id}/custom")
async def analyze_with_prompt(item_id: str, request: CustomPromptAnalysisRequest):
    """
    Analyze transcription using a custom prompt.

    Either provide a prompt_id to use a saved prompt, or prompt_text for ad-hoc analysis.

    Args:
        item_id: The transcription ID
        request: Contains prompt_id or prompt_text
    """
    api_key = get_api_key()
    if not api_key:
        raise HTTPException(status_code=400, detail="OpenAI API key not configured")

    # Get the prompt text
    prompt = None
    if request.prompt_id:
        prompts = get_custom_prompts()
        for p in prompts:
            if p["id"] == request.prompt_id:
                prompt = p["prompt"]
                break
        if not prompt:
            raise HTTPException(status_code=404, detail="Prompt not found")
    elif request.prompt_text:
        prompt = request.prompt_text
    else:
        raise HTTPException(status_code=400, detail="Either prompt_id or prompt_text is required")

    # Get transcription text
    item = get_history_item(item_id)
    text = None

    with jobs_lock:
        if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
            text = jobs[item_id]["text"]
        elif item:
            text = get_transcription_text(item['file_path'])

    if not text:
        raise HTTPException(status_code=404, detail="Transcription not found")

    if len(text.strip()) < 50:
        raise HTTPException(status_code=400, detail="Transcription too short to analyze")

    try:
        result = analyze_with_custom_prompt(text, api_key, prompt)
        return {"result": result, "prompt": prompt}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}")


# Full Item Detail (for detail page)
@router.get("/history/{item_id}/full")
async def get_full_item_detail(item_id: str):
    """
    Get complete item data including transcription, all analysis, Q&A history, resources, and costs.
    Used by the detail page to show everything in one place.
    """
    item = get_full_item(item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    # Also get topics
    topics = get_video_topics(item_id)
    item['topics'] = topics

    return item


# Save Q&A Answer
@router.post("/qa/{item_id}/save")
async def save_qa_answer(item_id: str, qa_data: dict):
    """
    Save a Q&A answer to the item's history.

    Args:
        item_id: The history item ID
        qa_data: Dict with question, answer, and optional cost_info, references
    """
    item = get_history_item(item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    question = qa_data.get('question', '')
    answer = qa_data.get('answer', '')
    cost_info = qa_data.get('cost_info')
    references = qa_data.get('references')

    if not question or not answer:
        raise HTTPException(status_code=400, detail="Question and answer are required")

    result = add_qa_entry(item_id, question, answer, cost_info, references)
    if result:
        return {"success": True, "qa_count": len(result.get('qa_history', []))}

    raise HTTPException(status_code=500, detail="Failed to save Q&A entry")


# Get Item Costs
@router.get("/history/{item_id}/costs")
async def get_history_item_costs(item_id: str):
    """Get all costs for an item."""
    item = get_history_item(item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    return get_item_costs(item_id)


# Save Resources
@router.post("/resources/{item_id}/save")
async def save_item_resources(item_id: str, resources_data: dict):
    """
    Save resources/citations to an item.

    Args:
        item_id: The history item ID
        resources_data: Dict with resources and optional cost_info
    """
    item = get_history_item(item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    resources = resources_data.get('resources', resources_data)
    cost_info = resources_data.get('cost_info')

    result = save_resources(item_id, resources, cost_info)
    if result:
        return {"success": True}

    raise HTTPException(status_code=500, detail="Failed to save resources")


# Full Export API Endpoints (includes analysis, Q&A, resources)
@router.get("/export-full/{item_id}")
async def export_item_full(item_id: str, format: str = "markdown"):
    """
    Export item data in various formats.

    Args:
        item_id: The item ID to export
        format: Export format - 'markdown', 'text', or 'json'

    Returns:
        File download response
    """
    from fastapi.responses import Response
    from ..services.export import (
        export_to_markdown,
        export_to_text,
        export_to_json,
        get_export_filename
    )

    item = get_full_item(item_id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    # Add topics to item
    topics = get_video_topics(item_id)
    item['topics'] = topics

    # Generate export content based on format
    format_lower = format.lower()
    if format_lower in ('markdown', 'md'):
        content = export_to_markdown(item)
        media_type = "text/markdown"
    elif format_lower in ('text', 'txt'):
        content = export_to_text(item)
        media_type = "text/plain"
    elif format_lower == 'json':
        content = export_to_json(item)
        media_type = "application/json"
    else:
        raise HTTPException(status_code=400, detail=f"Unsupported format: {format}. Use 'markdown', 'text', or 'json'")

    filename = get_export_filename(item, format_lower)

    return Response(
        content=content.encode('utf-8'),
        media_type=media_type,
        headers={
            "Content-Disposition": f'attachment; filename="{filename}"'
        }
    )


# Debug API Endpoints
@router.get("/debug/log")
async def get_debug_log(limit: int = 50):
    """
    Get recent debug log entries showing API requests and responses.
    Useful for troubleshooting API issues.
    """
    from ..services.debug import get_debug_log, is_debug_enabled
    return {
        "enabled": is_debug_enabled(),
        "entries": get_debug_log(limit)
    }


@router.get("/debug/log/{request_id}")
async def get_debug_entry(request_id: str):
    """Get a specific debug entry by request ID."""
    from ..services.debug import get_debug_entry
    entry = get_debug_entry(request_id)
    if not entry.get("request"):
        raise HTTPException(status_code=404, detail="Request not found")
    return entry


@router.post("/debug/clear")
async def clear_debug_log():
    """Clear all debug log entries."""
    from ..services.debug import clear_debug_log
    clear_debug_log()
    return {"success": True}


@router.post("/debug/toggle")
async def toggle_debug_mode(enabled: bool = True):
    """Enable or disable debug logging."""
    from ..services.debug import set_debug_enabled
    set_debug_enabled(enabled)
    return {"debug_enabled": enabled}
