"""Transcription API routes."""

import uuid
from pathlib import Path
from threading import Thread, Lock
from collections import deque
from fastapi import APIRouter, HTTPException
from fastapi.responses import PlainTextResponse

from ..models import (
    TranscribeRequest,
    TranscribeResponse,
    StatusResponse,
    ResultResponse,
    JobStatus,
    VideoPreviewRequest,
    VideoPreview,
    QueueRequest,
    QueueStatusResponse,
    HistoryResponse,
    HistoryItem,
    ExportFormat,
)
from ..config import get_api_key, get_output_directory, get_temp_dir
from ..services.downloader import download_audio, get_video_info
from ..services.transcriber import transcribe_audio, cleanup_audio, text_to_srt, text_to_vtt
from ..services.history import (
    add_to_history, get_history, get_history_item,
    delete_history_item, get_transcription_text, clear_history
)
from ..services.analyzer import analyze_transcription, translate_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)

        # 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')
        )

        # Cleanup
        cleanup_audio(file_path)

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

    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")
        # Cleanup on error
        if file_path:
            try:
                cleanup_audio(file_path)
            except:
                pass

    # 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()


# 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))


# 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)


# 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")
    )


# 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'])
    return {**item, "text": text}


@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
    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"]
        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']
            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"'}
        )
    else:
        raise HTTPException(status_code=400, detail="Unsupported format")


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

    analysis_type can be: "full", "summary", "takeaways", or "topics"
    """
    api_key = get_api_key()
    if not api_key:
        raise HTTPException(status_code=400, detail="OpenAI API key not configured")

    # Get transcription text
    with jobs_lock:
        if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
            text = jobs[item_id]["text"]
        else:
            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'])
            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_transcription(text, api_key, analysis_type)
        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.

    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")

    # Get transcription text
    with jobs_lock:
        if item_id in jobs and jobs[item_id]["status"] == JobStatus.COMPLETE:
            text = jobs[item_id]["text"]
        else:
            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'])
            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)
        return {"translation": translated, "target_language": target_language}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Translation failed: {str(e)}")
