from datetime import datetime
from typing import Optional

from bson import ObjectId
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile, status
from motor.motor_asyncio import AsyncIOMotorDatabase

from ...core.config import settings
from ...core.database import get_database
from ...core.dependencies import get_current_user, require_roles
from ...core.logging import get_logger
from ...lib.vtt import VTTEditor
from ...models.job import JobStatus, RequestedOutputs
from ...models.user import User, UserRole
from ...schemas.job import (
    ApproveEnglishRequest,
    ApproveSourceRequest,
    AssetValidationResponse,
    BulkDeleteRequest,
    BulkDeleteResponse,
    CompleteJobRequest,
    JobDeleteResponse,
    JobDownloadsResponse,
    JobListResponse,
    JobResponse,
    RejectJobRequest,
    VttContentResponse,
    VttTimingAdjustRequest,
    VttUpdateRequest,
)
from ...services.websocket import connection_manager
from ...services.gcs import (
    gcs_service,
    upload_file_to_gcs,
    upload_vtt_to_gcs,
)
from ...services.validation import asset_validation_service
from ...tasks import celery_app
from ...tasks.ingest_and_ai import ingest_and_ai_task
from ...tasks.translate_and_synthesize import translate_and_synthesize_task

logger = get_logger(__name__)
router = APIRouter(prefix="/jobs", tags=["jobs"])


@router.post("", response_model=JobResponse, status_code=status.HTTP_201_CREATED)
async def create_job(
    title: str = Form(...),
    source_is_english: bool = Form(True),  # True = English source, False = other language (auto-detect)
    language_hint: Optional[str] = Form(None),  # Optional hint when source_is_english=False
    requested_outputs: str = Form(...),  # JSON string
    file: UploadFile = File(...),
    current_user: User = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    # Validate file type
    if not file.content_type or not file.content_type.startswith("video/"):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="File must be a video"
        )

    # Parse requested outputs
    import json
    try:
        outputs_data = json.loads(requested_outputs)
        outputs = RequestedOutputs(**outputs_data)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid requested_outputs format"
        )

    # Generate job ID and upload file
    job_id = str(ObjectId())
    gcs_uri = await upload_file_to_gcs(
        file, f"{job_id}/source.mp4"
    )

    # Determine initial language setting
    # If English: set to "en"
    # If not English: set to "auto" (will be detected by AI) or use hint
    initial_language = "en" if source_is_english else (language_hint or "auto")

    # Create job document
    job_data = {
        "_id": job_id,
        "client_id": str(current_user.id),
        "title": title,
        "source": {
            "filename": f"{job_id}/source.mp4",
            "original_filename": file.filename,
            "gcs_uri": gcs_uri,
            "language": initial_language,
            "language_hint": language_hint if not source_is_english else None,
        },
        "requested_outputs": outputs.dict(),
        "status": JobStatus.CREATED.value,
        "review": {
            "notes": "",
            "history": [{
                "at": datetime.utcnow(),
                "status": JobStatus.CREATED.value,
                "by": "system"
            }]
        },
        "created_at": datetime.utcnow(),
        "updated_at": datetime.utcnow()
    }

    await db.jobs.insert_one(job_data)

    # Enqueue processing task
    logger.info(f"Dispatching ingest_and_ai_task for job {job_id}")
    logger.info(f"Using Celery app: {celery_app}")
    logger.info(f"Task object: {ingest_and_ai_task}")
    logger.info(f"Task routing config: {celery_app.conf.task_routes}")
    try:
        # Use apply_async for more control and debugging
        task = ingest_and_ai_task.apply_async(args=[job_id], queue='ingest')
        logger.info(f"Task dispatched successfully: {task.id} for job {job_id} to queue 'ingest'")
        logger.info(f"Task state: {task.state}")
        logger.info(f"Task backend: {task.backend}")

        # Try to get the task result to see if it was actually queued
        try:
            # This should timeout quickly since task just started
            import time
            time.sleep(1)  # Give it a moment
            task_info = task.state
            logger.info(f"Task state after 1 second: {task_info}")

            # Check celery inspect to see active/scheduled tasks
            from celery import current_app
            i = current_app.control.inspect()
            active_tasks = i.active()
            scheduled_tasks = i.scheduled()
            logger.info(f"Active tasks across all workers: {active_tasks}")
            logger.info(f"Scheduled tasks across all workers: {scheduled_tasks}")

        except Exception as e:
            logger.warning(f"Could not inspect task status: {e}")

        # Store task ID in job document for monitoring
        await db.jobs.update_one(
            {"_id": job_id},
            {"$set": {"task_id": task.id}}
        )

    except Exception as e:
        logger.error(f"Failed to dispatch task for job {job_id}: {e} (type: {e.__class__.__name__})")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to start processing: {e}"
        )

    return JobResponse(
        id=job_id,
        title=title,
        status=JobStatus.CREATED,
        source=job_data["source"],
        requested_outputs=outputs,
        review=job_data["review"],
        created_at=job_data["created_at"].isoformat(),
        updated_at=job_data["updated_at"].isoformat()
    )


@router.delete("/bulk", response_model=BulkDeleteResponse)
async def bulk_delete_jobs(
    request: BulkDeleteRequest,
    current_user: User = Depends(require_roles(UserRole.PRODUCTION, UserRole.ADMIN)),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Bulk delete jobs (production/admin only)"""
    job_ids = request.job_ids
    logger.info(f"Bulk deleting {len(job_ids)} jobs requested by {current_user.email}")

    deleted_count = 0
    errors = []

    for job_id in job_ids:
        try:
            job_doc = await db.jobs.find_one({"_id": job_id})
            if not job_doc:
                errors.append(f"Job {job_id}: not found")
                continue

            # Cancel task if exists
            task_id = job_doc.get("task_id")
            if task_id:
                try:
                    celery_app.control.revoke(task_id, terminate=True)
                except Exception as e:
                    logger.warning(f"Could not cancel task {task_id} for job {job_id}: {e}")

            # Delete GCS assets
            await _delete_job_gcs_assets(job_id, job_doc)

            # Delete from database
            result = await db.jobs.delete_one({"_id": job_id})
            if result.deleted_count > 0:
                deleted_count += 1
                logger.info(f"Deleted job {job_id}")
            else:
                errors.append(f"Job {job_id}: database deletion failed")

        except Exception as e:
            errors.append(f"Job {job_id}: {str(e)}")
            logger.error(f"Failed to delete job {job_id}: {e}")

    return {
        "deleted_count": deleted_count,
        "total_requested": len(job_ids),
        "errors": errors
    }


@router.get("", response_model=JobListResponse)
async def list_jobs(
    status: Optional[str] = None,
    mine: bool = False,
    page: int = 1,
    size: int = 20,
    current_user: User = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    print(f"🔍 DEBUG: list_jobs called by user {current_user.id}, status={status}, mine={mine}")
    try:
        query = {}

        if status:
            if ',' in status:
                # Handle comma-separated status values
                status_list = [s.strip() for s in status.split(',')]
                query["status"] = {"$in": status_list}
            else:
                query["status"] = status

        if mine or current_user.role == UserRole.CLIENT:
            query["client_id"] = str(current_user.id)

        # Get total count
        total = await db.jobs.count_documents(query)

        # Get paginated results
        skip = (page - 1) * size
        cursor = db.jobs.find(query).sort("created_at", -1).skip(skip).limit(size)
        jobs = await cursor.to_list(length=size)

        job_responses = []
        print(f"🔍 DEBUG: Found {len(jobs)} jobs, building responses...")
        for i, job_doc in enumerate(jobs):
            try:
                print(f"🔍 DEBUG: Processing job {i}: {job_doc.get('_id')}")
                job_responses.append(JobResponse(
                    id=str(job_doc["_id"]),
                    title=job_doc["title"],
                    status=job_doc["status"],
                    source=job_doc["source"],
                    requested_outputs=RequestedOutputs(**job_doc["requested_outputs"]),
                    review=job_doc.get("review", {"notes": "", "history": []}),
                    outputs=job_doc.get("outputs"),
                    created_at=job_doc["created_at"].isoformat(),
                    updated_at=job_doc["updated_at"].isoformat()
                ))
                print(f"🔍 DEBUG: Job {i} processed successfully")
            except Exception as e:
                print(f"🚨 ERROR processing job {i}: {e}")
                import traceback
                print(traceback.format_exc())
                raise

        print(f"🔍 DEBUG: All jobs processed, returning response")
        return JobListResponse(
            jobs=job_responses,
            total=total,
            page=page,
            size=size
        )
    except Exception as e:
        print(f"🚨 EXCEPTION in list_jobs: {e}")
        import traceback
        print(traceback.format_exc())
        raise


@router.get("/{job_id}", response_model=JobResponse)
async def get_job(
    job_id: str,
    current_user: User = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    job_doc = await db.jobs.find_one({"_id": job_id})
    if not job_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found"
        )

    # Check access permissions
    if (current_user.role == UserRole.CLIENT and
        job_doc["client_id"] != str(current_user.id)):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Access denied"
        )

    # Check task status if task_id exists
    task_id = job_doc.get("task_id")
    if task_id and job_doc["status"] == JobStatus.CREATED.value:
        try:
            task_result = celery_app.AsyncResult(task_id)
            if task_result.failed():
                logger.error(f"Task {task_id} failed for job {job_id} - State: {task_result.state}, Error: {task_result.result}")
                # Update job status to reflect task failure
                await db.jobs.update_one(
                    {"_id": job_id},
                    {
                        "$set": {
                            "error": {
                                "type": "task_failure",
                                "message": str(task_result.result) if task_result.result else "Unknown task failure",
                                "timestamp": datetime.utcnow().isoformat()
                            },
                            "updated_at": datetime.utcnow()
                        }
                    }
                )
        except Exception as e:
            logger.warning(f"Could not check task status for job {job_id}: {e}")

    return JobResponse(
        id=str(job_doc["_id"]),
        title=job_doc["title"],
        status=job_doc["status"],
        source=job_doc["source"],
        requested_outputs=RequestedOutputs(**job_doc["requested_outputs"]),
        review=job_doc.get("review", {"notes": "", "history": []}),
        outputs=job_doc.get("outputs"),
        created_at=job_doc["created_at"].isoformat(),
        updated_at=job_doc["updated_at"].isoformat()
    )


@router.post("/{job_id}/actions/approve_source", response_model=JobResponse)
async def approve_source(
    job_id: str,
    request: ApproveSourceRequest,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.PRODUCTION, UserRole.ADMIN)),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Approve the source language version (works for any language)"""
    # First, get the job to determine the source language
    job_doc = await db.jobs.find_one({"_id": job_id})
    if not job_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found"
        )

    if job_doc["status"] != JobStatus.PENDING_QC.value:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Job not in pending QC status"
        )

    # Determine the appropriate status based on source language
    source_language = job_doc["source"].get("language", "en")
    new_status = JobStatus.APPROVED_ENGLISH if source_language == "en" else JobStatus.APPROVED_SOURCE

    # Build update operations
    update_set = {
        "status": new_status.value,
        "review.notes": request.notes or "",
        "review.reviewer_id": str(current_user.id),
        "updated_at": datetime.utcnow()
    }

    # If TTS preferences override provided, update requested_outputs.tts_preferences
    if request.tts_preferences:
        update_set["requested_outputs.tts_preferences"] = request.tts_preferences.model_dump()
        logger.info(f"Updating TTS preferences for job {job_id}: {request.tts_preferences}")

    result = await db.jobs.find_one_and_update(
        {"_id": job_id, "status": JobStatus.PENDING_QC.value},
        {
            "$set": update_set,
            "$push": {
                "review.history": {
                    "at": datetime.utcnow(),
                    "status": new_status.value,
                    "by": str(current_user.id),
                    "notes": request.notes or ""
                }
            }
        },
        return_document=True
    )

    if not result:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found or not in pending QC status"
        )

    # Trigger translation and synthesis pipeline immediately
    try:
        translate_and_synthesize_task.delay(job_id)
        logger.info(f"Triggered translation task for approved job {job_id} (source: {source_language})")
    except Exception as e:
        logger.error(f"Failed to trigger translation task for job {job_id}: {e}")
        # Don't fail the approval, just log the error

    return JobResponse(
        id=str(result["_id"]),
        title=result["title"],
        status=result["status"],
        source=result["source"],
        requested_outputs=RequestedOutputs(**result["requested_outputs"]),
        review=result.get("review", {"notes": "", "history": []}),
        outputs=result.get("outputs"),
        created_at=result["created_at"].isoformat(),
        updated_at=result["updated_at"].isoformat()
    )


@router.post("/{job_id}/actions/approve_english", response_model=JobResponse)
async def approve_english(
    job_id: str,
    request: ApproveEnglishRequest,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.PRODUCTION, UserRole.ADMIN)),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Legacy endpoint - redirects to approve_source for backwards compatibility"""
    return await approve_source(
        job_id,
        ApproveSourceRequest(notes=request.notes),
        current_user,
        db
    )


@router.post("/{job_id}/actions/reject", response_model=JobResponse)
async def reject_job(
    job_id: str,
    request: RejectJobRequest,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.PRODUCTION, UserRole.ADMIN)),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    result = await db.jobs.find_one_and_update(
        {"_id": job_id, "status": JobStatus.PENDING_QC.value},
        {
            "$set": {
                "status": JobStatus.REJECTED.value,
                "review.notes": request.notes,
                "review.reviewer_id": str(current_user.id),
                "updated_at": datetime.utcnow()
            },
            "$push": {
                "review.history": {
                    "at": datetime.utcnow(),
                    "status": JobStatus.REJECTED.value,
                    "by": str(current_user.id),
                    "notes": request.notes
                }
            }
        },
        return_document=True
    )

    if not result:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found or not in pending QC status"
        )

    return JobResponse(
        id=str(result["_id"]),
        title=result["title"],
        status=result["status"],
        source=result["source"],
        requested_outputs=RequestedOutputs(**result["requested_outputs"]),
        review=result.get("review", {"notes": "", "history": []}),
        outputs=result.get("outputs"),
        created_at=result["created_at"].isoformat(),
        updated_at=result["updated_at"].isoformat()
    )


@router.post("/{job_id}/actions/complete", response_model=JobResponse)
async def complete_job(
    job_id: str,
    request: CompleteJobRequest,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.PRODUCTION, UserRole.ADMIN)),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    # Get job for validation
    job_doc = await db.jobs.find_one({"_id": job_id})
    if not job_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found"
        )

    if job_doc["status"] != JobStatus.PENDING_FINAL_REVIEW.value:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Job not ready for completion"
        )

    # Validate all assets before completion
    is_valid, validation_errors = await asset_validation_service.validate_job_assets(job_doc)
    if not is_valid:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Asset validation failed: {'; '.join(validation_errors)}"
        )

    result = await db.jobs.find_one_and_update(
        {"_id": job_id, "status": JobStatus.PENDING_FINAL_REVIEW.value},
        {
            "$set": {
                "status": JobStatus.COMPLETED.value,
                "review.notes": request.notes or "",
                "updated_at": datetime.utcnow()
            },
            "$push": {
                "review.history": {
                    "at": datetime.utcnow(),
                    "status": JobStatus.COMPLETED.value,
                    "by": str(current_user.id),
                    "notes": request.notes or ""
                }
            }
        },
        return_document=True
    )

    if not result:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found or not in pending final review status"
        )


    # Trigger client notification task now that job is completed
    try:
        from ...tasks.notify import notify_client_task
        notify_client_task.delay(job_id)
        logger.info(f"Triggered client notification task for completed job {job_id}")
    except Exception as e:
        logger.warning(f"Failed to trigger client notification task for job {job_id}: {e}")

    return JobResponse(
        id=str(result["_id"]),
        title=result["title"],
        status=result["status"],
        source=result["source"],
        requested_outputs=RequestedOutputs(**result["requested_outputs"]),
        review=result.get("review", {"notes": "", "history": []}),
        outputs=result.get("outputs"),
        created_at=result["created_at"].isoformat(),
        updated_at=result["updated_at"].isoformat()
    )


@router.post("/{job_id}/actions/reject_final", response_model=JobResponse)
async def reject_final_review(
    job_id: str,
    request: RejectJobRequest,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.PRODUCTION, UserRole.ADMIN)),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    result = await db.jobs.find_one_and_update(
        {"_id": job_id, "status": JobStatus.PENDING_FINAL_REVIEW.value},
        {
            "$set": {
                "status": JobStatus.QC_FEEDBACK.value,
                "review.notes": request.notes,
                "review.reviewer_id": str(current_user.id),
                "updated_at": datetime.utcnow()
            },
            "$push": {
                "review.history": {
                    "at": datetime.utcnow(),
                    "status": JobStatus.QC_FEEDBACK.value,
                    "by": str(current_user.id),
                    "notes": request.notes
                }
            }
        },
        return_document=True
    )

    if not result:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found or not in pending final review status"
        )


    return JobResponse(
        id=str(result["_id"]),
        title=result["title"],
        status=result["status"],
        source=result["source"],
        requested_outputs=RequestedOutputs(**result["requested_outputs"]),
        review=result.get("review", {"notes": "", "history": []}),
        outputs=result.get("outputs"),
        created_at=result["created_at"].isoformat(),
        updated_at=result["updated_at"].isoformat()
    )


@router.get("/{job_id}/downloads", response_model=JobDownloadsResponse)
async def get_job_downloads(
    job_id: str,
    current_user: User = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    from ...services.gcs import get_signed_download_url

    job_doc = await db.jobs.find_one({"_id": job_id})
    if not job_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found"
        )

    # Check access permissions (only client or admin/reviewer can download)
    if (current_user.role == UserRole.CLIENT and
        job_doc["client_id"] != str(current_user.id)):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Access denied"
        )

    # Allow downloads for jobs that have outputs available
    # (PENDING_QC, APPROVED_ENGLISH, TRANSLATING, COMPLETED, etc.)
    if job_doc["status"] in [JobStatus.CREATED.value, JobStatus.INGESTING.value, JobStatus.AI_PROCESSING.value]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Job is still being processed"
        )

    # Check if job has outputs
    if not job_doc.get("outputs"):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="No outputs available for this job"
        )

    # Generate signed URLs for all outputs
    downloads = {}

    # Add source video URL
    if job_doc.get("source", {}).get("gcs_uri"):
        source_blob_path = job_doc["source"]["gcs_uri"].replace(f"gs://{settings.gcs_bucket}/", "")
        try:
            source_signed_url = await get_signed_download_url(source_blob_path, 24)
            downloads["source_video"] = source_signed_url
        except Exception as e:
            logger.warning(f"Failed to generate signed URL for source video: {e}")

    outputs = job_doc.get("outputs", {})

    for language, lang_output in outputs.items():
        if not isinstance(lang_output, dict):
            continue

        lang_downloads = {}

        # Captions VTT
        if "captions_vtt_gcs" in lang_output:
            blob_path = lang_output["captions_vtt_gcs"].replace(f"gs://{settings.gcs_bucket}/", "")
            try:
                signed_url = await get_signed_download_url(blob_path, 24)
                lang_downloads["captions_vtt"] = signed_url
            except Exception as e:
                logger.warning(f"Failed to generate signed URL for captions {language}: {e}")

        # Audio Description VTT
        if "ad_vtt_gcs" in lang_output:
            blob_path = lang_output["ad_vtt_gcs"].replace(f"gs://{settings.gcs_bucket}/", "")
            try:
                signed_url = await get_signed_download_url(blob_path, 24)
                lang_downloads["audio_description_vtt"] = signed_url
            except Exception as e:
                logger.warning(f"Failed to generate signed URL for AD VTT {language}: {e}")

        # Audio Description MP3
        if "ad_mp3_gcs" in lang_output:
            blob_path = lang_output["ad_mp3_gcs"].replace(f"gs://{settings.gcs_bucket}/", "")
            try:
                signed_url = await get_signed_download_url(blob_path, 24)
                lang_downloads["audio_description_mp3"] = signed_url
            except Exception as e:
                logger.warning(f"Failed to generate signed URL for AD MP3 {language}: {e}")

        if lang_downloads:
            downloads[language] = lang_downloads

    return JobDownloadsResponse(downloads=downloads)


@router.get("/{job_id}/vtt", response_model=VttContentResponse)
async def get_job_vtt_content(
    job_id: str,
    language: Optional[str] = None,  # If None, defaults to source language
    current_user: User = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Get VTT content for editing. If language is not specified, returns source language content."""
    job_doc = await db.jobs.find_one({"_id": job_id})
    if not job_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found"
        )

    # Check access permissions
    if (current_user.role == UserRole.CLIENT and
        job_doc["client_id"] != str(current_user.id)):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Access denied"
        )

    # Default to source language if not specified
    target_language = language or job_doc["source"].get("language", "en")

    outputs = job_doc.get("outputs", {})
    lang_output = outputs.get(target_language, {})

    response = VttContentResponse()

    # Fetch captions VTT if available
    if "captions_vtt_gcs" in lang_output:
        blob_path = lang_output["captions_vtt_gcs"].replace(f"gs://{settings.gcs_bucket}/", "")
        try:
            blob = gcs_service.bucket.blob(blob_path)
            response.captions_vtt = blob.download_as_text()
        except Exception as e:
            logger.warning(f"Failed to fetch captions VTT: {e}")

    # Fetch audio description VTT if available
    if "ad_vtt_gcs" in lang_output:
        blob_path = lang_output["ad_vtt_gcs"].replace(f"gs://{settings.gcs_bucket}/", "")
        try:
            blob = gcs_service.bucket.blob(blob_path)
            response.audio_description_vtt = blob.download_as_text()
        except Exception as e:
            logger.warning(f"Failed to fetch AD VTT: {e}")

    return response


@router.patch("/{job_id}/vtt", response_model=JobResponse)
async def update_job_vtt_content(
    job_id: str,
    request: VttUpdateRequest,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.PRODUCTION, UserRole.ADMIN)),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Update VTT content for a job. If language is not specified, updates source language content."""
    job_doc = await db.jobs.find_one({"_id": job_id})
    if not job_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found"
        )

    # Only allow editing during QC phase
    if job_doc["status"] not in [JobStatus.PENDING_QC.value, JobStatus.QC_FEEDBACK.value]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="VTT content can only be edited during QC phase"
        )

    # Default to source language if not specified
    target_language = request.language or job_doc["source"].get("language", "en")

    outputs = job_doc.get("outputs", {})
    lang_output = outputs.get(target_language, {})

    # Validate and update captions VTT
    if request.captions_vtt is not None:
        # Validate VTT format
        is_valid, errors = VTTEditor.validate_vtt(request.captions_vtt)
        if not is_valid:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Invalid captions VTT: {'; '.join(errors)}"
            )

        # Upload updated VTT
        new_captions_uri = await upload_vtt_to_gcs(
            request.captions_vtt,
            f"{job_id}/{target_language}/captions.vtt"
        )
        lang_output["captions_vtt_gcs"] = new_captions_uri

    # Validate and update audio description VTT
    if request.audio_description_vtt is not None:
        # Validate VTT format
        is_valid, errors = VTTEditor.validate_vtt(request.audio_description_vtt)
        if not is_valid:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Invalid audio description VTT: {'; '.join(errors)}"
            )

        # Upload updated VTT
        new_ad_uri = await upload_vtt_to_gcs(
            request.audio_description_vtt,
            f"{job_id}/{target_language}/ad.vtt"
        )
        lang_output["ad_vtt_gcs"] = new_ad_uri

    # Update job with new VTT content
    outputs[target_language] = lang_output

    result = await db.jobs.find_one_and_update(
        {"_id": job_id},
        {
            "$set": {
                "outputs": outputs,
                "updated_at": datetime.utcnow()
            },
            "$push": {
                "review.history": {
                    "at": datetime.utcnow(),
                    "status": "vtt_updated",
                    "by": str(current_user.id),
                    "notes": f"Updated VTT content for {target_language}"
                }
            }
        },
        return_document=True
    )

    return JobResponse(
        id=str(result["_id"]),
        title=result["title"],
        status=result["status"],
        source=result["source"],
        requested_outputs=RequestedOutputs(**result["requested_outputs"]),
        review=result.get("review", {"notes": "", "history": []}),
        outputs=result.get("outputs"),
        created_at=result["created_at"].isoformat(),
        updated_at=result["updated_at"].isoformat()
    )


@router.post("/{job_id}/vtt/adjust-timing", response_model=JobResponse)
async def adjust_vtt_timing(
    job_id: str,
    request: VttTimingAdjustRequest,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.PRODUCTION, UserRole.ADMIN)),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Adjust timing of VTT content by a specified offset"""
    job_doc = await db.jobs.find_one({"_id": job_id})
    if not job_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found"
        )

    # Only allow timing adjustment during QC phase
    if job_doc["status"] not in [JobStatus.PENDING_QC.value, JobStatus.QC_FEEDBACK.value]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="VTT timing can only be adjusted during QC phase"
        )

    # Get current VTT content from GCS
    lang_key = request.language
    outputs = job_doc.get("outputs", {}).get(lang_key, {})

    if not outputs:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"No VTT content found for language: {request.language}"
        )

    update_operations = {}
    adjusted_content = {}

    # Adjust captions VTT if requested and exists
    if request.adjust_captions and "captions_vtt_gcs" in outputs:
        try:
            # Download current captions VTT
            captions_blob = gcs_service.bucket.blob(
                outputs["captions_vtt_gcs"].replace(f"gs://{settings.gcs_bucket}/", "")
            )
            current_captions_vtt = captions_blob.download_as_text()

            # Apply timing adjustment
            adjusted_captions_vtt = VTTEditor.adjust_timing_offset(
                current_captions_vtt,
                request.offset_seconds
            )

            # Upload adjusted content back to GCS
            new_captions_gcs_uri = await upload_vtt_to_gcs(
                adjusted_captions_vtt,
                f"{job_id}/{request.language}/captions.vtt"
            )

            update_operations[f"outputs.{lang_key}.captions_vtt_gcs"] = new_captions_gcs_uri
            adjusted_content["captions"] = True

        except Exception as e:
            logger.error(f"Failed to adjust captions timing: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="Failed to adjust captions timing"
            )

    # Adjust audio description VTT if requested and exists
    if request.adjust_audio_description and "ad_vtt_gcs" in outputs:
        try:
            # Download current AD VTT
            ad_blob = gcs_service.bucket.blob(
                outputs["ad_vtt_gcs"].replace(f"gs://{settings.gcs_bucket}/", "")
            )
            current_ad_vtt = ad_blob.download_as_text()

            # Apply timing adjustment
            adjusted_ad_vtt = VTTEditor.adjust_timing_offset(
                current_ad_vtt,
                request.offset_seconds
            )

            # Upload adjusted content back to GCS
            new_ad_gcs_uri = await upload_vtt_to_gcs(
                adjusted_ad_vtt,
                f"{job_id}/{request.language}/ad.vtt"
            )

            update_operations[f"outputs.{lang_key}.ad_vtt_gcs"] = new_ad_gcs_uri
            adjusted_content["audio_description"] = True

        except Exception as e:
            logger.error(f"Failed to adjust audio description timing: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="Failed to adjust audio description timing"
            )

    if not update_operations:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="No VTT content to adjust"
        )

    # Update job document
    result = await db.jobs.find_one_and_update(
        {"_id": job_id},
        {
            "$set": {
                **update_operations,
                "updated_at": datetime.utcnow()
            },
            "$push": {
                "review.history": {
                    "at": datetime.utcnow(),
                    "status": "timing_adjusted",
                    "by": str(current_user.id),
                    "notes": f"Adjusted timing by {request.offset_seconds:+.1f}s for {', '.join(adjusted_content.keys())}"
                }
            }
        },
        return_document=True
    )

    return JobResponse(
        id=str(result["_id"]),
        title=result["title"],
        status=result["status"],
        source=result["source"],
        requested_outputs=RequestedOutputs(**result["requested_outputs"]),
        review=result.get("review", {"notes": "", "history": []}),
        outputs=result.get("outputs"),
        created_at=result["created_at"].isoformat(),
        updated_at=result["updated_at"].isoformat()
    )


@router.delete("/{job_id}", response_model=JobDeleteResponse)
async def delete_job(
    job_id: str,
    current_user: User = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Delete a job and all associated assets"""
    job_doc = await db.jobs.find_one({"_id": job_id})
    if not job_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found"
        )

    # Check permissions: clients can only delete their own jobs, admins/reviewers can delete any
    if (current_user.role == UserRole.CLIENT and
        job_doc["client_id"] != str(current_user.id)):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Access denied"
        )

    logger.info(f"Deleting job {job_id} requested by {current_user.email}")

    try:
        # 1. Cancel running Celery task if exists
        task_id = job_doc.get("task_id")
        if task_id:
            try:
                celery_app.control.revoke(task_id, terminate=True)
                logger.info(f"Cancelled Celery task {task_id} for job {job_id}")
            except Exception as e:
                logger.warning(f"Could not cancel task {task_id}: {e}")

        # 2. Delete GCS assets
        await _delete_job_gcs_assets(job_id, job_doc)

        # 3. Delete from database
        result = await db.jobs.delete_one({"_id": job_id})

        if result.deleted_count == 0:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Job not found"
            )

        logger.info(f"Successfully deleted job {job_id}")
        return {"message": f"Job {job_id} deleted successfully"}

    except Exception as e:
        logger.error(f"Failed to delete job {job_id}: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to delete job: {str(e)}"
        )


async def _delete_job_gcs_assets(job_id: str, job_doc: dict):
    """Delete all GCS assets for a job"""
    try:
        # Delete source file
        source_gcs_uri = job_doc.get("source", {}).get("gcs_uri")
        if source_gcs_uri:
            blob_path = source_gcs_uri.replace(f"gs://{settings.gcs_bucket}/", "")
            try:
                blob = gcs_service.bucket.blob(blob_path)
                blob.delete()
                logger.info(f"Deleted source file: {blob_path}")
            except Exception as e:
                logger.warning(f"Could not delete source file {blob_path}: {e}")

        # Delete output files
        outputs = job_doc.get("outputs", {})
        for lang, lang_outputs in outputs.items():
            if not isinstance(lang_outputs, dict):
                continue

            # Delete VTT files
            for key in ["captions_vtt_gcs", "ad_vtt_gcs", "ad_mp3_gcs"]:
                if key in lang_outputs:
                    gcs_uri = lang_outputs[key]
                    blob_path = gcs_uri.replace(f"gs://{settings.gcs_bucket}/", "")
                    try:
                        blob = gcs_service.bucket.blob(blob_path)
                        blob.delete()
                        logger.info(f"Deleted output file: {blob_path}")
                    except Exception as e:
                        logger.warning(f"Could not delete output file {blob_path}: {e}")

        # Delete entire job folder if it exists
        try:
            blobs = gcs_service.bucket.list_blobs(prefix=f"{job_id}/")
            for blob in blobs:
                try:
                    blob.delete()
                    logger.info(f"Deleted remaining file: {blob.name}")
                except Exception as e:
                    logger.warning(f"Could not delete {blob.name}: {e}")
        except Exception as e:
            logger.warning(f"Could not list/delete job folder {job_id}/: {e}")

    except Exception as e:
        logger.error(f"Error deleting GCS assets for job {job_id}: {e}")
        raise


@router.get("/{job_id}/validate", response_model=AssetValidationResponse)
async def validate_job_assets(
    job_id: str,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.PRODUCTION, UserRole.ADMIN)),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Validate job assets before completion"""
    job_doc = await db.jobs.find_one({"_id": job_id})
    if not job_doc:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Job not found"
        )

    is_valid, errors = await asset_validation_service.validate_job_assets(job_doc)

    return AssetValidationResponse(
        is_valid=is_valid,
        errors=errors,
        warnings=[]  # Can be extended for non-blocking warnings
    )
