import os
from fastapi import APIRouter, BackgroundTasks, HTTPException
from app.models.schemas import (
    ProcessRequest, ProcessResponse, JobStatus, SubtitleStyle,
    TrimRequest, TrimResponse, VideoInfoResponse,
    TranscribeRequest, RenderRequest,
)
from app.models.job_store import job_store
from app.services.transcriber import transcribe_video, segments_to_ass
from app.services.translator import translate_segments, TranslationMode
from app.services.video_processor import process_video, trim_video, get_video_info, get_video_duration, extract_frame
from app.services.thumbnail import generate_thumbnail, generate_catchphrase, get_video_timestamps
from app.config import settings

router = APIRouter()


async def process_task(
    job_id: str,
    bgm_id: str | None,
    bgm_volume: float,
    subtitle_style: SubtitleStyle | None,
    keep_original_audio: bool,
    translation_mode: str | None = None,
    use_vocal_separation: bool = False,
):
    """Background task for full video processing pipeline."""
    job = job_store.get_job(job_id)
    if not job or not job.video_path:
        job_store.update_job(job_id, status=JobStatus.FAILED, error="Job or video not found")
        return

    try:
        # Progress callback for real-time status updates
        async def progress_callback(step: str, progress: int):
            step_to_status = {
                "vocal_separation": JobStatus.EXTRACTING_AUDIO,
                "extracting_audio": JobStatus.EXTRACTING_AUDIO,
                "noise_reduction": JobStatus.NOISE_REDUCTION,
                "transcribing": JobStatus.TRANSCRIBING,
            }
            status = step_to_status.get(step, JobStatus.TRANSCRIBING)
            print(f"[Progress] Step: {step} -> Status: {status}, Progress: {progress}%")
            job_store.update_job(job_id, status=status, progress=progress)

        # Start with initial status
        job_store.update_job(job_id, status=JobStatus.EXTRACTING_AUDIO, progress=10)

        success, message, segments, detected_lang = await transcribe_video(
            job.video_path,
            use_noise_reduction=True,
            noise_reduction_level="medium",
            use_vocal_separation=use_vocal_separation,
            progress_callback=progress_callback,
        )

        # Handle special cases
        if not success:
            if message in ("NO_AUDIO", "SILENT_AUDIO", "SINGING_ONLY"):
                # Video has no usable speech - allow manual subtitle input or BGM-only processing
                if message == "NO_AUDIO":
                    audio_status = "no_audio_stream"
                elif message == "SILENT_AUDIO":
                    audio_status = "audio_silent"
                else:  # SINGING_ONLY
                    audio_status = "singing_only"

                job_store.update_job(
                    job_id,
                    status=JobStatus.AWAITING_SUBTITLE,
                    progress=35,
                    has_audio=message != "NO_AUDIO",  # Has audio if it's singing
                    audio_status=audio_status,
                )
                return
            else:
                job_store.update_job(job_id, status=JobStatus.FAILED, error=message)
                return

        # Audio OK - speech detected and transcribed
        job_store.update_job(job_id, transcript=segments, progress=50, has_audio=True, audio_status="ok", detected_language=detected_lang)

        # Step 2: Translate/Rewrite (only for Chinese content)
        # Check if the detected language is Chinese (zh, zh-cn, zh-tw, chinese)
        is_chinese = detected_lang and detected_lang.lower() in ['zh', 'zh-cn', 'zh-tw', 'chinese', 'mandarin']

        if is_chinese:
            job_store.update_job(job_id, status=JobStatus.TRANSLATING, progress=55)

            mode = translation_mode or settings.TRANSLATION_MODE
            success, message, segments = await translate_segments(
                segments,
                mode=mode,
                max_tokens=settings.TRANSLATION_MAX_TOKENS,
            )
            if not success:
                # Continue with original text if translation fails
                print(f"Translation warning: {message}")

            job_store.update_job(job_id, transcript=segments, progress=70)
        else:
            # Skip translation for non-Chinese content - just use original text as-is
            print(f"Skipping GPT translation for non-Chinese content (detected: {detected_lang})")
            # Set translated to original text for subtitle generation
            for seg in segments:
                seg.translated = seg.text
            job_store.update_job(job_id, transcript=segments, progress=70)

        # Step 3: Generate subtitle file
        style = subtitle_style or SubtitleStyle()
        subtitle_content = segments_to_ass(
            segments,
            use_translated=True,
            font_size=style.font_size,
            font_color=style.font_color.lstrip("#"),
            outline_color=style.outline_color.lstrip("#"),
            font_name=style.font_name,
            position=style.position,  # top, center, bottom
            outline_width=style.outline_width,
            bold=style.bold,
            shadow=style.shadow,
            background_box=style.background_box,
            background_opacity=style.background_opacity,
            animation=style.animation,
        )

        # Save subtitle file
        job_dir = os.path.dirname(job.video_path)
        subtitle_path = os.path.join(job_dir, "subtitle.ass")
        with open(subtitle_path, "w", encoding="utf-8") as f:
            f.write(subtitle_content)

        # Step 4: Process video
        job_store.update_job(job_id, status=JobStatus.PROCESSING, progress=75)

        # Determine BGM path
        bgm_path = None
        if bgm_id:
            bgm_path = os.path.join(settings.BGM_DIR, f"{bgm_id}.mp3")
            if not os.path.exists(bgm_path):
                bgm_path = os.path.join(settings.BGM_DIR, f"{bgm_id}.wav")

        # Output path
        output_dir = os.path.join(settings.PROCESSED_DIR, job_id)
        os.makedirs(output_dir, exist_ok=True)
        output_path = os.path.join(output_dir, "output.mp4")

        success, message = await process_video(
            input_path=job.video_path,
            output_path=output_path,
            subtitle_path=subtitle_path,
            bgm_path=bgm_path,
            bgm_volume=bgm_volume,
            keep_original_audio=keep_original_audio,
        )

        if success:
            job_store.update_job(
                job_id,
                status=JobStatus.COMPLETED,
                output_path=output_path,
                progress=100,
            )
        else:
            job_store.update_job(job_id, status=JobStatus.FAILED, error=message)

    except Exception as e:
        job_store.update_job(job_id, status=JobStatus.FAILED, error=str(e))


@router.post("/", response_model=ProcessResponse)
async def start_processing(
    request: ProcessRequest,
    background_tasks: BackgroundTasks
):
    """Start video processing (transcribe, translate, add subtitles/BGM)."""
    job = job_store.get_job(request.job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")

    if not job.video_path:
        raise HTTPException(status_code=400, detail="Video not downloaded yet")

    if job.status == JobStatus.DOWNLOADING:
        raise HTTPException(status_code=400, detail="Download still in progress")

    # Start background processing
    background_tasks.add_task(
        process_task,
        request.job_id,
        request.bgm_id,
        request.bgm_volume,
        request.subtitle_style,
        request.keep_original_audio,
        request.translation_mode,
        request.use_vocal_separation,
    )

    mode_info = f" (mode: {request.translation_mode or settings.TRANSLATION_MODE})"
    vocal_sep_info = ", vocal separation" if request.use_vocal_separation else ""
    return ProcessResponse(
        job_id=request.job_id,
        status=JobStatus.TRANSCRIBING,
        message=f"Processing started{mode_info}{vocal_sep_info}"
    )


@router.post("/{job_id}/transcribe")
async def transcribe_only(job_id: str, background_tasks: BackgroundTasks):
    """Transcribe video only (without full processing)."""
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")
    if not job.video_path:
        raise HTTPException(status_code=400, detail="Video not downloaded yet")

    async def transcribe_task():
        job_store.update_job(job_id, status=JobStatus.TRANSCRIBING, progress=35)
        success, message, segments = await transcribe_video(job.video_path)

        if success:
            job_store.update_job(
                job_id,
                transcript=segments,
                status=JobStatus.PENDING,
                progress=50,
            )
        else:
            job_store.update_job(job_id, status=JobStatus.FAILED, error=message)

    background_tasks.add_task(transcribe_task)
    return {"message": "Transcription started"}


@router.put("/{job_id}/transcript")
async def update_transcript(job_id: str, segments: list[dict]):
    """Update transcript segments (for manual editing)."""
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")

    from app.models.schemas import TranscriptSegment
    updated_segments = []
    for seg in segments:
        # Handle both dict and Pydantic model-like objects
        if hasattr(seg, 'model_dump'):
            seg = seg.model_dump()
        updated_segments.append(TranscriptSegment(**seg))
    job_store.update_job(job_id, transcript=updated_segments)

    return {"message": "Transcript updated"}


async def continue_processing_task(
    job_id: str,
    bgm_id: str | None,
    bgm_volume: float,
    subtitle_style: SubtitleStyle | None,
    keep_original_audio: bool,
    skip_subtitle: bool = False,
):
    """Continue processing for jobs that were awaiting subtitle input."""
    job = job_store.get_job(job_id)
    if not job or not job.video_path:
        job_store.update_job(job_id, status=JobStatus.FAILED, error="Job or video not found")
        return

    try:
        subtitle_path = None

        if not skip_subtitle and job.transcript:
            # Generate subtitle file from existing transcript
            job_store.update_job(job_id, status=JobStatus.PROCESSING, progress=60)

            style = subtitle_style or SubtitleStyle()
            subtitle_content = segments_to_ass(
                job.transcript,
                use_translated=True,
                font_size=style.font_size,
                font_color=style.font_color.lstrip("#"),
                outline_color=style.outline_color.lstrip("#"),
                font_name=style.font_name,
                position=style.position,
                outline_width=style.outline_width,
                bold=style.bold,
                shadow=style.shadow,
                background_box=style.background_box,
                background_opacity=style.background_opacity,
                animation=style.animation,
            )

            job_dir = os.path.dirname(job.video_path)
            subtitle_path = os.path.join(job_dir, "subtitle.ass")
            with open(subtitle_path, "w", encoding="utf-8") as f:
                f.write(subtitle_content)
        else:
            # Skip subtitle - process with BGM only
            job_store.update_job(job_id, status=JobStatus.PROCESSING, progress=60)

        # Process video
        job_store.update_job(job_id, progress=75)

        bgm_path = None
        if bgm_id:
            bgm_path = os.path.join(settings.BGM_DIR, f"{bgm_id}.mp3")
            if not os.path.exists(bgm_path):
                bgm_path = os.path.join(settings.BGM_DIR, f"{bgm_id}.wav")

        output_dir = os.path.join(settings.PROCESSED_DIR, job_id)
        os.makedirs(output_dir, exist_ok=True)
        output_path = os.path.join(output_dir, "output.mp4")

        success, message = await process_video(
            input_path=job.video_path,
            output_path=output_path,
            subtitle_path=subtitle_path,
            bgm_path=bgm_path,
            bgm_volume=bgm_volume,
            keep_original_audio=keep_original_audio and job.has_audio,  # Only keep if has audio
        )

        if success:
            job_store.update_job(
                job_id,
                status=JobStatus.COMPLETED,
                output_path=output_path,
                progress=100,
            )
        else:
            job_store.update_job(job_id, status=JobStatus.FAILED, error=message)

    except Exception as e:
        job_store.update_job(job_id, status=JobStatus.FAILED, error=str(e))


@router.post("/{job_id}/continue")
async def continue_processing(
    job_id: str,
    request: ProcessRequest,
    background_tasks: BackgroundTasks,
):
    """Continue or reprocess a job (supports awaiting_subtitle and completed status)."""
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")

    # 허용된 상태: awaiting_subtitle (음성없음), completed (재처리)
    allowed_statuses = [JobStatus.AWAITING_SUBTITLE, JobStatus.COMPLETED]
    if job.status not in allowed_statuses:
        raise HTTPException(
            status_code=400,
            detail=f"Job status must be 'awaiting_subtitle' or 'completed', current: {job.status}"
        )

    background_tasks.add_task(
        continue_processing_task,
        job_id,
        request.bgm_id,
        request.bgm_volume,
        request.subtitle_style,
        request.keep_original_audio,
        skip_subtitle=not job.transcript,  # Skip if no transcript
    )

    mode = "reprocessing" if job.status == JobStatus.COMPLETED else "no audio mode"
    return ProcessResponse(
        job_id=job_id,
        status=JobStatus.PROCESSING,
        message=f"Continuing processing ({mode})"
    )


@router.post("/{job_id}/manual-subtitle")
async def add_manual_subtitle(
    job_id: str,
    segments: list,
    background_tasks: BackgroundTasks,
):
    """Add manual subtitle segments and continue processing."""
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")

    if job.status != JobStatus.AWAITING_SUBTITLE:
        raise HTTPException(
            status_code=400,
            detail=f"Job status must be 'awaiting_subtitle', current: {job.status}"
        )

    # Parse and save the manual segments
    from app.models.schemas import TranscriptSegment
    manual_segments = [TranscriptSegment(**seg) for seg in segments]
    job_store.update_job(job_id, transcript=manual_segments)

    return {"message": "Manual subtitles added", "segment_count": len(manual_segments)}


@router.get("/{job_id}/video-info", response_model=VideoInfoResponse)
async def get_job_video_info(job_id: str):
    """Get video information for trimming UI."""
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")
    if not job.video_path or not os.path.exists(job.video_path):
        raise HTTPException(status_code=400, detail="Video file not found")

    info = await get_video_info(job.video_path)
    if not info:
        # Fallback to just duration
        duration = await get_video_duration(job.video_path)
        if duration is None:
            raise HTTPException(status_code=500, detail="Could not get video info")
        info = {"duration": duration}

    return VideoInfoResponse(
        duration=info.get("duration", 0),
        width=info.get("width"),
        height=info.get("height"),
    )


@router.get("/{job_id}/frame")
async def get_frame_at_timestamp(job_id: str, timestamp: float):
    """
    Extract a single frame at the specified timestamp.
    Returns the frame as a JPEG image.
    Used for precise trimming preview.
    """
    from fastapi.responses import FileResponse
    import tempfile

    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")
    if not job.video_path or not os.path.exists(job.video_path):
        raise HTTPException(status_code=400, detail="Video file not found")

    # Get video duration to validate timestamp
    duration = await get_video_duration(job.video_path)
    if duration is None:
        raise HTTPException(status_code=500, detail="Could not get video duration")

    # Clamp timestamp to valid range
    timestamp = max(0, min(timestamp, duration - 0.01))

    # Create temp file for frame
    temp_dir = tempfile.gettempdir()
    frame_path = os.path.join(temp_dir, f"frame_{job_id}_{timestamp:.3f}.jpg")

    success, message = await extract_frame(job.video_path, frame_path, timestamp)

    if not success:
        raise HTTPException(status_code=500, detail=message)

    return FileResponse(
        path=frame_path,
        media_type="image/jpeg",
        headers={
            "Cache-Control": "public, max-age=60",
        }
    )


@router.post("/{job_id}/trim", response_model=TrimResponse)
async def trim_job_video(
    job_id: str,
    request: TrimRequest,
    background_tasks: BackgroundTasks,
):
    """
    Trim video to specified time range and optionally reprocess.

    This creates a new trimmed video file, replacing the original.
    Use this to remove sections with unwanted content (like original subtitles).
    """
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")
    if not job.video_path or not os.path.exists(job.video_path):
        raise HTTPException(status_code=400, detail="Video file not found")

    # Validate time range
    duration = await get_video_duration(job.video_path)
    if duration is None:
        raise HTTPException(status_code=500, detail="Could not get video duration")

    if request.start_time < 0 or request.end_time > duration:
        raise HTTPException(
            status_code=400,
            detail=f"Invalid time range. Video duration is {duration:.1f}s"
        )
    if request.start_time >= request.end_time:
        raise HTTPException(
            status_code=400,
            detail="Start time must be less than end time"
        )

    # Update status
    job_store.update_job(job_id, status=JobStatus.TRIMMING, progress=5)

    # Create trimmed video path
    video_dir = os.path.dirname(job.video_path)
    video_ext = os.path.splitext(job.video_path)[1]
    trimmed_path = os.path.join(video_dir, f"trimmed{video_ext}")

    # Perform trim
    success, message = await trim_video(
        job.video_path,
        trimmed_path,
        request.start_time,
        request.end_time,
    )

    if not success:
        job_store.update_job(job_id, status=JobStatus.FAILED, error=message)
        return TrimResponse(
            job_id=job_id,
            success=False,
            message=message,
        )

    # Replace original with trimmed video
    original_path = job.video_path
    backup_path = os.path.join(video_dir, f"original_backup{video_ext}")

    try:
        # Backup original
        os.rename(original_path, backup_path)
        # Move trimmed to original location
        os.rename(trimmed_path, original_path)
        # Remove backup
        os.remove(backup_path)
    except Exception as e:
        job_store.update_job(job_id, status=JobStatus.FAILED, error=f"File operation failed: {e}")
        return TrimResponse(
            job_id=job_id,
            success=False,
            message=f"File operation failed: {e}",
        )

    # Get new duration
    new_duration = await get_video_duration(original_path)

    # Reset job state for next step
    job_store.update_job(
        job_id,
        status=JobStatus.READY_FOR_TRIM,  # Stay in trim-ready state for manual workflow
        progress=30,
        transcript=None,  # Clear old transcript
        output_path=None,  # Clear old output
        error=None,
    )

    # Optionally start reprocessing
    if request.reprocess:
        background_tasks.add_task(
            process_task,
            job_id,
            None,  # bgm_id
            0.3,  # bgm_volume
            None,  # subtitle_style
            True,  # keep_original_audio
            None,  # translation_mode
            False,  # use_vocal_separation
        )
        message = f"Video trimmed to {new_duration:.1f}s. Reprocessing started."
    else:
        message = f"Video trimmed to {new_duration:.1f}s. Ready for processing."

    return TrimResponse(
        job_id=job_id,
        success=True,
        message=message,
        new_duration=new_duration,
    )


# ============================================================
# Step-by-step Processing API (Manual Workflow)
# ============================================================

async def transcribe_step_task(
    job_id: str,
    translation_mode: str | None = None,
    use_vocal_separation: bool = False,
):
    """Background task for transcription step only (audio extraction + STT + translation)."""
    job = job_store.get_job(job_id)
    if not job or not job.video_path:
        job_store.update_job(job_id, status=JobStatus.FAILED, error="Job or video not found")
        return

    try:
        # Progress callback for real-time status updates
        async def progress_callback(step: str, progress: int):
            step_to_status = {
                "vocal_separation": JobStatus.EXTRACTING_AUDIO,
                "extracting_audio": JobStatus.EXTRACTING_AUDIO,
                "noise_reduction": JobStatus.NOISE_REDUCTION,
                "transcribing": JobStatus.TRANSCRIBING,
            }
            status = step_to_status.get(step, JobStatus.TRANSCRIBING)
            print(f"[Progress] Step: {step} -> Status: {status}, Progress: {progress}%")
            job_store.update_job(job_id, status=status, progress=progress)

        # Start with initial status
        job_store.update_job(job_id, status=JobStatus.EXTRACTING_AUDIO, progress=10)

        success, message, segments, detected_lang = await transcribe_video(
            job.video_path,
            use_noise_reduction=True,
            noise_reduction_level="medium",
            use_vocal_separation=use_vocal_separation,
            progress_callback=progress_callback,
        )

        # Handle special cases
        if not success:
            if message in ("NO_AUDIO", "SILENT_AUDIO", "SINGING_ONLY"):
                if message == "NO_AUDIO":
                    audio_status = "no_audio_stream"
                elif message == "SILENT_AUDIO":
                    audio_status = "audio_silent"
                else:
                    audio_status = "singing_only"

                job_store.update_job(
                    job_id,
                    status=JobStatus.AWAITING_SUBTITLE,
                    progress=35,
                    has_audio=message != "NO_AUDIO",
                    audio_status=audio_status,
                )
                return
            else:
                job_store.update_job(job_id, status=JobStatus.FAILED, error=message)
                return

        # Audio OK - speech detected and transcribed
        job_store.update_job(job_id, transcript=segments, progress=50, has_audio=True, audio_status="ok", detected_language=detected_lang)

        # Translate/Rewrite (only for Chinese content)
        is_chinese = detected_lang and detected_lang.lower() in ['zh', 'zh-cn', 'zh-tw', 'chinese', 'mandarin']

        if is_chinese:
            job_store.update_job(job_id, status=JobStatus.TRANSLATING, progress=55)

            mode = translation_mode or settings.TRANSLATION_MODE
            success, message, segments = await translate_segments(
                segments,
                mode=mode,
                max_tokens=settings.TRANSLATION_MAX_TOKENS,
            )
            if not success:
                print(f"Translation warning: {message}")

            job_store.update_job(job_id, transcript=segments, progress=70)
        else:
            # Skip translation for non-Chinese content
            print(f"Skipping GPT translation for non-Chinese content (detected: {detected_lang})")
            for seg in segments:
                seg.translated = seg.text
            job_store.update_job(job_id, transcript=segments, progress=70)

        # STOP HERE - Set status to AWAITING_REVIEW for user to review script
        job_store.update_job(
            job_id,
            status=JobStatus.AWAITING_REVIEW,
            progress=70,
        )

    except Exception as e:
        job_store.update_job(job_id, status=JobStatus.FAILED, error=str(e))


async def render_step_task(
    job_id: str,
    bgm_id: str | None,
    bgm_volume: float,
    subtitle_style: SubtitleStyle | None,
    keep_original_audio: bool,
    intro_text: str | None = None,
    intro_duration: float = 0.7,
    intro_font_size: int = 100,
):
    """Background task for final video rendering (subtitle composition + BGM + intro text)."""
    job = job_store.get_job(job_id)
    if not job or not job.video_path:
        job_store.update_job(job_id, status=JobStatus.FAILED, error="Job or video not found")
        return

    try:
        subtitle_path = None

        if job.transcript:
            # Generate subtitle file from transcript
            job_store.update_job(job_id, status=JobStatus.PROCESSING, progress=75)

            style = subtitle_style or SubtitleStyle()
            # When intro text is shown, delay subtitles so they don't overlap
            subtitle_offset = intro_duration if intro_text else 0.0
            subtitle_content = segments_to_ass(
                job.transcript,
                use_translated=True,
                font_size=style.font_size,
                font_color=style.font_color.lstrip("#"),
                outline_color=style.outline_color.lstrip("#"),
                font_name=style.font_name,
                position=style.position,
                outline_width=style.outline_width,
                bold=style.bold,
                shadow=style.shadow,
                background_box=style.background_box,
                background_opacity=style.background_opacity,
                animation=style.animation,
                time_offset=subtitle_offset,
            )

            job_dir = os.path.dirname(job.video_path)
            subtitle_path = os.path.join(job_dir, "subtitle.ass")
            with open(subtitle_path, "w", encoding="utf-8") as f:
                f.write(subtitle_content)
        else:
            # No subtitle - BGM only mode
            job_store.update_job(job_id, status=JobStatus.PROCESSING, progress=75)

        # Determine BGM path
        bgm_path = None
        if bgm_id:
            bgm_path = os.path.join(settings.BGM_DIR, f"{bgm_id}.mp3")
            if not os.path.exists(bgm_path):
                bgm_path = os.path.join(settings.BGM_DIR, f"{bgm_id}.wav")

        # Output path
        output_dir = os.path.join(settings.PROCESSED_DIR, job_id)
        os.makedirs(output_dir, exist_ok=True)
        output_path = os.path.join(output_dir, "output.mp4")

        job_store.update_job(job_id, progress=80)

        success, message = await process_video(
            input_path=job.video_path,
            output_path=output_path,
            subtitle_path=subtitle_path,
            bgm_path=bgm_path,
            bgm_volume=bgm_volume,
            keep_original_audio=keep_original_audio,
            intro_text=intro_text,
            intro_duration=intro_duration,
            intro_font_size=intro_font_size,
        )

        if success:
            job_store.update_job(
                job_id,
                status=JobStatus.COMPLETED,
                output_path=output_path,
                progress=100,
            )
        else:
            job_store.update_job(job_id, status=JobStatus.FAILED, error=message)

    except Exception as e:
        job_store.update_job(job_id, status=JobStatus.FAILED, error=str(e))


@router.post("/{job_id}/start-transcription", response_model=ProcessResponse)
async def start_transcription(
    job_id: str,
    request: TranscribeRequest,
    background_tasks: BackgroundTasks,
):
    """
    Start transcription step (audio extraction + STT + translation).
    After completion, job status will be 'awaiting_review' for user to review the script.
    """
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")
    if not job.video_path:
        raise HTTPException(status_code=400, detail="Video not downloaded yet")

    # Allow starting from ready_for_trim or pending status
    allowed_statuses = [JobStatus.READY_FOR_TRIM, JobStatus.PENDING]
    if job.status not in allowed_statuses:
        raise HTTPException(
            status_code=400,
            detail=f"Job status must be 'ready_for_trim' or 'pending', current: {job.status}"
        )

    background_tasks.add_task(
        transcribe_step_task,
        job_id,
        request.translation_mode,
        request.use_vocal_separation,
    )

    return ProcessResponse(
        job_id=job_id,
        status=JobStatus.EXTRACTING_AUDIO,
        message="Transcription started. Script will be ready for review."
    )


@router.post("/{job_id}/render", response_model=ProcessResponse)
async def render_video(
    job_id: str,
    request: RenderRequest,
    background_tasks: BackgroundTasks,
):
    """
    Render final video with subtitles and BGM.
    Call this after reviewing and editing the script.
    """
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")
    if not job.video_path:
        raise HTTPException(status_code=400, detail="Video not found")

    # Allow rendering from awaiting_review, awaiting_subtitle, or completed (re-render)
    allowed_statuses = [JobStatus.AWAITING_REVIEW, JobStatus.AWAITING_SUBTITLE, JobStatus.COMPLETED]
    if job.status not in allowed_statuses:
        raise HTTPException(
            status_code=400,
            detail=f"Job status must be 'awaiting_review', 'awaiting_subtitle', or 'completed', current: {job.status}"
        )

    background_tasks.add_task(
        render_step_task,
        job_id,
        request.bgm_id,
        request.bgm_volume,
        request.subtitle_style,
        request.keep_original_audio,
        request.intro_text,
        request.intro_duration,
        request.intro_font_size,
    )

    return ProcessResponse(
        job_id=job_id,
        status=JobStatus.PROCESSING,
        message="Final video rendering started."
    )


@router.post("/{job_id}/retranslate")
async def retranslate(job_id: str, background_tasks: BackgroundTasks):
    """
    Re-run GPT translation on existing transcript segments.
    Useful when user wants to regenerate the Korean script.
    """
    import logging
    logger = logging.getLogger(__name__)

    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")
    if not job.transcript:
        raise HTTPException(status_code=400, detail="No transcript found. Run transcription first.")

    # Copy segments to avoid reference issues
    segments_copy = [seg.model_copy() for seg in job.transcript]
    logger.info(f"[Retranslate] Starting for job {job_id} with {len(segments_copy)} segments")

    async def retranslate_task():
        try:
            logger.info(f"[Retranslate] Background task started for job {job_id}")
            job_store.update_job(job_id, status=JobStatus.TRANSLATING, progress=55)

            # Reset translations
            for seg in segments_copy:
                seg.translated = None

            mode = settings.TRANSLATION_MODE
            logger.info(f"[Retranslate] Using mode: {mode}")

            success, message, translated_segments = await translate_segments(
                segments_copy,
                mode=mode,
                max_tokens=settings.TRANSLATION_MAX_TOKENS,
            )

            logger.info(f"[Retranslate] Translation result: success={success}, message={message}")

            if success:
                job_store.update_job(
                    job_id,
                    transcript=translated_segments,
                    status=JobStatus.AWAITING_REVIEW,
                    progress=70,
                )
                logger.info(f"[Retranslate] Job {job_id} updated with new translation")
            else:
                job_store.update_job(job_id, status=JobStatus.FAILED, error=message)
                logger.error(f"[Retranslate] Translation failed: {message}")

        except Exception as e:
            logger.exception(f"[Retranslate] Exception in retranslate_task: {e}")
            job_store.update_job(job_id, status=JobStatus.FAILED, error=str(e))

    # Use asyncio.create_task to properly run async background task
    import asyncio
    asyncio.create_task(retranslate_task())

    return {"message": "Re-translation started", "job_id": job_id}


@router.post("/{job_id}/skip-trim", response_model=ProcessResponse)
async def skip_trim(job_id: str):
    """
    Skip the trimming step and proceed to transcription.
    Updates status from 'ready_for_trim' to 'pending'.
    """
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")

    if job.status != JobStatus.READY_FOR_TRIM:
        raise HTTPException(
            status_code=400,
            detail=f"Job status must be 'ready_for_trim', current: {job.status}"
        )

    job_store.update_job(job_id, status=JobStatus.PENDING)

    return ProcessResponse(
        job_id=job_id,
        status=JobStatus.PENDING,
        message="Trim skipped. Ready for transcription."
    )


# ============================================================
# Thumbnail Generation API
# ============================================================

@router.get("/{job_id}/thumbnail-timestamps")
async def get_thumbnail_timestamps(job_id: str, count: int = 5):
    """
    Get suggested timestamps for thumbnail frame selection.
    Returns evenly distributed timestamps from the video.
    """
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")
    if not job.video_path or not os.path.exists(job.video_path):
        raise HTTPException(status_code=400, detail="Video file not found")

    timestamps = await get_video_timestamps(job.video_path, count)

    return {
        "job_id": job_id,
        "timestamps": timestamps,
        "count": len(timestamps),
    }


@router.post("/{job_id}/generate-catchphrase")
async def api_generate_catchphrase(job_id: str, style: str = "homeshopping"):
    """
    Generate a catchy thumbnail text using GPT.

    Available styles:
    - homeshopping: 홈쇼핑 스타일 (강렬한 어필)
    - viral: 바이럴 스타일 (호기심 유발)
    - informative: 정보성 스타일 (명확한 전달)
    """
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")
    if not job.transcript:
        raise HTTPException(status_code=400, detail="No transcript found. Run transcription first.")

    success, message, catchphrase = await generate_catchphrase(job.transcript, style)

    if not success:
        raise HTTPException(status_code=500, detail=message)

    return {
        "job_id": job_id,
        "catchphrase": catchphrase,
        "style": style,
    }


@router.post("/{job_id}/thumbnail")
async def create_thumbnail(
    job_id: str,
    timestamp: float = 2.0,
    style: str = "homeshopping",
    custom_text: str | None = None,
    font_size: int = 80,
    position: str = "center",
):
    """
    Generate a thumbnail with text overlay.

    Args:
        timestamp: Time in seconds to extract frame (default: 2.0)
        style: Catchphrase style (homeshopping, viral, informative)
        custom_text: Custom text to use (skip GPT generation if provided)
        font_size: Font size for text overlay (default: 80)
        position: Text position (top, center, bottom)

    Returns:
        Thumbnail file path and the text used
    """
    job = job_store.get_job(job_id)

    if not job:
        raise HTTPException(status_code=404, detail="Job not found")
    if not job.video_path or not os.path.exists(job.video_path):
        raise HTTPException(status_code=400, detail="Video file not found")

    # Use empty transcript if not available
    transcript = job.transcript or []

    success, message, thumbnail_path = await generate_thumbnail(
        job_id=job_id,
        video_path=job.video_path,
        transcript=transcript,
        timestamp=timestamp,
        style=style,
        custom_text=custom_text,
        font_size=font_size,
        position=position,
    )

    if not success:
        raise HTTPException(status_code=500, detail=message)

    # Extract text from message
    text_used = message.replace("Thumbnail generated: ", "")

    return {
        "job_id": job_id,
        "thumbnail_path": thumbnail_path,
        "thumbnail_url": f"/api/jobs/{job_id}/thumbnail",
        "text": text_used,
        "timestamp": timestamp,
    }
