"""Text-to-speech generation using edge-tts."""

import asyncio
import logging
import tempfile
from pathlib import Path
from typing import Any

import edge_tts

logger = logging.getLogger(__name__)

# Available voices (subset of edge-tts voices)
VOICES = {
    "en-US-male": "en-US-GuyNeural",
    "en-US-female": "en-US-JennyNeural",
    "en-US-aria": "en-US-AriaNeural",
    "en-GB-male": "en-GB-RyanNeural",
    "en-GB-female": "en-GB-SoniaNeural",
    "en-AU-male": "en-AU-WilliamNeural",
    "en-AU-female": "en-AU-NatashaNeural",
}

DEFAULT_VOICE = "en-US-GuyNeural"


async def generate_narration(
    text: str,
    output_path: str | Path | None = None,
    voice: str = DEFAULT_VOICE,
    rate: str = "+0%",
    pitch: str = "+0Hz",
) -> dict[str, Any]:
    """Generate audio narration from text.

    Args:
        text: Text to convert to speech
        output_path: Output file path (mp3). Auto-generated if None.
        voice: Voice to use (name or alias from VOICES)
        rate: Speech rate adjustment (e.g., "+10%", "-5%")
        pitch: Pitch adjustment (e.g., "+5Hz", "-10Hz")

    Returns:
        Dict with path, duration, and metadata
    """
    # Resolve voice alias
    if voice in VOICES:
        voice = VOICES[voice]

    # Generate output path if needed
    output_path = Path(tempfile.mktemp(suffix=".mp3")) if output_path is None else Path(output_path)

    output_path.parent.mkdir(parents=True, exist_ok=True)

    logger.info(f"Generating narration with voice {voice}")

    try:
        communicate = edge_tts.Communicate(text, voice, rate=rate, pitch=pitch)
        await communicate.save(str(output_path))

        # Get audio duration using pydub
        try:
            from pydub import AudioSegment

            audio = AudioSegment.from_mp3(str(output_path))
            duration = len(audio) / 1000.0  # Convert ms to seconds
        except Exception:
            duration = None

        return {
            "success": True,
            "path": str(output_path),
            "duration": duration,
            "voice": voice,
            "text_length": len(text),
        }
    except Exception as e:
        logger.error(f"TTS generation failed: {e}")
        return {
            "success": False,
            "error": str(e),
        }


async def generate_synced_narration(
    segments: list[dict[str, Any]],
    output_path: str | Path | None = None,
    voice: str = DEFAULT_VOICE,
    target_duration: float | None = None,
) -> dict[str, Any]:
    """Generate narration from timed segments.

    Args:
        segments: List of {"text": str, "start": float, "end": float}
        output_path: Output file path
        voice: Voice to use
        target_duration: Target total duration (paces speech to match)

    Returns:
        Dict with path and segment timings
    """
    if not segments:
        return {"success": False, "error": "No segments provided"}

    # Combine all text
    full_text = " ".join(seg["text"] for seg in segments)

    # Generate base audio
    result = await generate_narration(full_text, output_path, voice)

    if not result["success"]:
        return result

    # If target duration specified, adjust speed
    if target_duration and result.get("duration"):
        current_duration = result["duration"]

        if abs(current_duration - target_duration) > 1:  # More than 1 second difference
            speed_factor = current_duration / target_duration

            # Adjust using pydub
            try:
                from pydub import AudioSegment

                # Verify audio loads (validates the file)
                AudioSegment.from_mp3(result["path"])

                # Speed up/slow down
                if speed_factor > 1:
                    # Need to speed up (increase rate)
                    rate = f"+{int((speed_factor - 1) * 100)}%"
                else:
                    # Need to slow down (decrease rate)
                    rate = f"-{int((1 - speed_factor) * 100)}%"

                # Regenerate with adjusted rate
                adjusted_result = await generate_narration(full_text, output_path, voice, rate=rate)

                result.update(adjusted_result)
                result["speed_adjusted"] = True
                result["speed_factor"] = speed_factor

            except Exception as e:
                logger.warning(f"Speed adjustment failed: {e}")
                result["speed_adjusted"] = False

    result["segment_count"] = len(segments)
    return result


async def list_voices() -> list[dict[str, str]]:
    """List available TTS voices.

    Returns:
        List of voice dicts with name, locale, gender
    """
    voices = await edge_tts.list_voices()

    return [
        {
            "name": v["Name"],
            "locale": v["Locale"],
            "gender": v["Gender"],
            "friendly_name": v.get("FriendlyName", v["Name"]),
        }
        for v in voices
        if v["Locale"].startswith("en-")  # English voices only
    ]


async def generate_narration_parallel(
    text: str,
    render_task: asyncio.Task | None = None,
    output_path: str | Path | None = None,
    voice: str = DEFAULT_VOICE,
) -> dict[str, Any]:
    """Generate narration in parallel with video rendering.

    This allows audio generation to happen while the video is being rendered,
    saving total processing time.

    Args:
        text: Narration text
        render_task: Optional asyncio task for video rendering
        output_path: Output path for audio
        voice: Voice to use

    Returns:
        Dict with audio result and timing info
    """
    import time

    start_time = time.time()

    # Generate audio
    audio_result = await generate_narration(text, output_path, voice)

    audio_time = time.time() - start_time

    # Wait for render if provided
    render_time = 0
    if render_task:
        render_start = time.time()
        await render_task
        render_time = time.time() - render_start

    total_time = time.time() - start_time

    return {
        **audio_result,
        "timing": {
            "audio_generation": audio_time,
            "render_wait": render_time,
            "total": total_time,
            "parallel_savings": max(0, audio_time - (total_time - render_time)),
        },
    }
