"""
Export utilities for integrating audio duration with video assembly.

Fetches actual audio durations from the database and applies
synchronization filters to the export pipeline.
"""

from __future__ import annotations

import logging
from pathlib import Path
from typing import Optional

logger = logging.getLogger(__name__)


async def fetch_scene_audio_durations(
    project_id: str,
    scenes: list[dict],
    get_audios_func,
) -> dict[int, float]:
    """
    Fetch actual audio durations for each scene from the database.
    
    Args:
        project_id: Project ID
        scenes: List of scene dicts with scene_number
        get_audios_func: Async function to fetch audios (e.g., get_project_audios)
    
    Returns: Dict mapping scene_number -> duration_seconds
    """
    audios = await get_audios_func(project_id) or []
    audio_durations = {}
    
    for audio in audios:
        scene_num = audio.get("scene_number")
        duration = audio.get("duration_seconds")
        if scene_num is not None and duration is not None:
            audio_durations[scene_num] = duration
            logger.debug(f"Scene {scene_num}: actual audio duration = {duration:.2f}s")
    
    return audio_durations


def calculate_total_video_duration(
    video_clips: list[dict],
    transitions: list[dict],
) -> float:
    """
    Calculate total video duration from clips and transitions.
    
    Accounts for transition overlaps (e.g., 0.3s crossfade reduces total by 0.3s)
    
    Returns: Total duration in seconds
    """
    if not video_clips:
        return 0.0
    
    # Sum clip durations
    total = sum(clip.get("duration", 3.0) for clip in video_clips)
    
    # Subtract transition overlaps
    for trans in transitions:
        trans_dur = trans.get("duration", 0.5)
        total -= trans_dur
    
    return max(0.1, total)  # Ensure positive minimum


def build_audio_filter_chain(
    audio_duration: float,
    video_duration: float,
    audio_clip_count: int = 1,
    transition_duration: float = 0.3,
) -> tuple[str, list[str]]:
    """
    Build FFmpeg audio filter chain to sync with video duration.
    
    Returns: (filter_string, notes_for_logging)
    """
    from providers.audio_sync import DurationReconciler
    
    if audio_duration <= 0 or video_duration <= 0:
        logger.warning(f"Invalid durations: audio={audio_duration}, video={video_duration}")
        return "", []
    
    reconciler = DurationReconciler(audio_duration, video_duration)
    mismatch = reconciler.get_mismatch()
    
    notes = []
    filters = []
    
    if not mismatch.requires_adjustment:
        notes.append(f"Audio/video already in sync (diff: {mismatch.difference_seconds:.2f}s, {mismatch.percentage_diff:.1f}%)")
        return "", notes
    
    notes.append(f"Duration mismatch detected: {mismatch.percentage_diff:.1f}%")
    notes.append(f"Strategy: {mismatch.strategy}")
    notes.append(f"Adjustment factor: {mismatch.adjustment_factor:.3f}")
    
    # Build audio filters
    audio_filters = reconciler.get_audio_filters()
    
    if audio_filters:
        filters.extend(audio_filters)
        notes.append(f"Applying audio filters: {', '.join(audio_filters)}")
    
    padding = reconciler.get_padding_seconds()
    if padding > 0:
        # Pad with silence
        filters.append(f"apad=whole_dur={video_duration:.3f}")
        notes.append(f"Adding {padding:.2f}s of silence padding")
    
    filter_str = ",".join(filters) if filters else ""
    return filter_str, notes


def apply_audio_sync_to_ffmpeg_command(
    cmd: list[str],
    audio_filter_str: str,
    audio_label: Optional[str] = None,
) -> list[str]:
    """
    Integrate audio filter chain into existing FFmpeg command.
    
    Modifies the -filter_complex argument to include audio filters.
    
    Args:
        cmd: Current FFmpeg command list
        audio_filter_str: Audio filter chain from build_audio_filter_chain
        audio_label: Audio output label (e.g., "aout")
    
    Returns: Modified command list
    """
    if not audio_filter_str:
        return cmd
    
    # Find and modify -filter_complex argument
    try:
        fc_idx = cmd.index("-filter_complex")
        current_fc = cmd[fc_idx + 1]
        
        # Append audio filters to the filter complex
        # If audio_label is provided, wrap filter
        if audio_label:
            new_fc = f"{current_fc};[aout]{audio_filter_str}[asynced]"
            # Update the mapping to use [asynced] instead of [aout]
            if "-map" in cmd:
                map_idx = cmd.index("-map")
                for i in range(map_idx, len(cmd), 2):
                    if i + 1 < len(cmd) and cmd[i + 1] == "[aout]":
                        cmd[i + 1] = "[asynced]"
                        break
        else:
            new_fc = f"{current_fc};{audio_filter_str}"
        
        cmd[fc_idx + 1] = new_fc
        return cmd
    except (ValueError, IndexError) as e:
        logger.warning(f"Could not integrate audio filter: {e}")
        return cmd


def log_sync_details(
    project_id: str,
    scene_num: int,
    timeline_duration: float,
    actual_audio_duration: float,
    applied_filters: list[str],
) -> None:
    """Log audio/video sync details for debugging."""
    diff = actual_audio_duration - timeline_duration
    pct = (diff / timeline_duration * 100) if timeline_duration > 0 else 0
    
    logger.info(
        f"[Project {project_id}] Scene {scene_num}: "
        f"Timeline={timeline_duration:.2f}s, "
        f"Audio={actual_audio_duration:.2f}s, "
        f"Diff={diff:+.2f}s ({pct:+.1f}%)"
    )
    
    if applied_filters:
        logger.info(f"  Applied filters: {', '.join(applied_filters)}")
