"""Lip sync player module - orchestrates audio and animation."""
import json
import time
from pathlib import Path
from .config import CHARACTERS_DIR, OUTPUT_DIR
from .tts_engine import generate_speech_with_timing, create_lipsync_timeline
from .apng_generator import create_lipsync_sequence_apng


class LipsyncSession:
    """Manages a lip sync playback session."""

    def __init__(self, character_name: str):
        """
        Initialize a lip sync session for a character.

        Args:
            character_name: Name of the character directory
        """
        self.character_name = character_name
        self.character_dir = CHARACTERS_DIR / character_name

        if not self.character_dir.exists():
            raise ValueError(f"Character not found: {character_name}")

        # Load character config
        config_path = self.character_dir / "config.json"
        if config_path.exists():
            with open(config_path) as f:
                self.config = json.load(f)
        else:
            self.config = {"name": character_name}

        # Load available visemes
        self.visemes = {}
        for viseme_file in self.character_dir.glob("*.png"):
            viseme_name = viseme_file.stem
            self.visemes[viseme_name] = viseme_file

    def get_viseme_path(self, viseme: str) -> Path:
        """Get the path to a viseme image."""
        if viseme in self.visemes:
            return self.visemes[viseme]
        return self.visemes.get("rest", list(self.visemes.values())[0])

    def generate_lipsync(self, text: str, output_name: str = None) -> dict:
        """
        Generate a complete lip sync package for the given text.

        Args:
            text: Text to speak
            output_name: Optional name for output files

        Returns:
            dict with paths to audio, animation, and timing data
        """
        output_name = output_name or f"lipsync_{int(time.time())}"
        output_dir = OUTPUT_DIR / output_name
        output_dir.mkdir(parents=True, exist_ok=True)

        # Generate speech with timing
        speech_result = generate_speech_with_timing(
            text,
            output_path=output_dir / "audio.mp3"
        )

        if not speech_result["success"]:
            return {"success": False, "error": "Speech generation failed"}

        # Create timeline
        timeline = create_lipsync_timeline(text)

        # Extract viseme sequence
        viseme_sequence = [frame["viseme"] for frame in timeline]

        # Create APNG animation
        apng_path = create_lipsync_sequence_apng(
            viseme_sequence=viseme_sequence,
            viseme_images=self.visemes,
            output_path=output_dir / "animation.png",
            frame_delay=int(1000 / 24),  # 24 fps
            add_transitions=False
        )

        # Save timeline data
        timeline_path = output_dir / "timeline.json"
        with open(timeline_path, "w") as f:
            json.dump({
                "text": text,
                "character": self.character_name,
                "duration_ms": speech_result["duration_ms"],
                "frames": timeline,
                "audio_path": str(speech_result["path"]),
                "animation_path": str(apng_path)
            }, f, indent=2)

        return {
            "success": True,
            "output_dir": str(output_dir),
            "audio_path": str(speech_result["path"]),
            "animation_path": str(apng_path),
            "timeline_path": str(timeline_path),
            "duration_ms": speech_result["duration_ms"],
            "frame_count": len(timeline)
        }

    def get_streaming_data(self, text: str) -> dict:
        """
        Generate data for streaming-style playback.

        Returns timing and viseme data that can be used for
        real-time client-side animation.

        Args:
            text: Text to speak

        Returns:
            dict with streaming playback data
        """
        speech_result = generate_speech_with_timing(text)

        if not speech_result["success"]:
            return {"success": False, "error": "Speech generation failed"}

        # Get viseme URLs for client
        viseme_urls = {
            name: f"/characters/{self.character_name}/{name}.png"
            for name in self.visemes.keys()
        }

        return {
            "success": True,
            "text": text,
            "character": self.character_name,
            "duration_ms": speech_result["duration_ms"],
            "audio_url": f"/output/speech_{hash(text) % 100000}.mp3",
            "timings": speech_result["timings"],
            "viseme_urls": viseme_urls
        }


def create_streaming_response(character_name: str, text: str) -> dict:
    """
    Create a streaming-ready response for lip sync playback.

    This generates all the data needed for client-side playback
    where audio and viseme switching are synchronized in real-time.

    Args:
        character_name: Name of the character
        text: Text to speak

    Returns:
        dict with all playback data
    """
    try:
        session = LipsyncSession(character_name)
        return session.get_streaming_data(text)
    except Exception as e:
        return {"success": False, "error": str(e)}


def generate_full_lipsync(character_name: str, text: str) -> dict:
    """
    Generate a complete lip sync package.

    This creates audio, APNG animation, and timing data
    that can be used for synchronized playback.

    Args:
        character_name: Name of the character
        text: Text to speak

    Returns:
        dict with paths to all generated files
    """
    try:
        session = LipsyncSession(character_name)
        return session.generate_lipsync(text)
    except Exception as e:
        return {"success": False, "error": str(e)}
