"""
ASS Export Engine

Exports styled captions to Advanced SubStation Alpha format
with full animation support.
"""

import os
from typing import List, Optional
from datetime import timedelta

from uace.models import Caption, CaptionSegment, Word
from uace.styling.presets import StylePreset, AnimationStyle
from uace.config import ExportConfig


class ASSExporter:
    """
    Exports captions to ASS format with animations.
    
    ASS is the most powerful subtitle format, supporting:
    - Complex styling
    - Animations via override tags
    - Multiple layers
    - Karaoke timing
    """
    
    def __init__(self, preset: StylePreset, config: ExportConfig):
        self.preset = preset
        self.config = config
    
    def export(self, caption: Caption, output_path: str) -> None:
        """Export caption to ASS file."""
        with open(output_path, 'w', encoding='utf-8-sig') as f:
            f.write(self._generate_header())
            f.write(self._generate_styles())
            f.write(self._generate_events(caption))
    
    def _generate_header(self) -> str:
        """Generate ASS file header."""
        return (
            "[Script Info]\n"
            "; Script generated by UACE\n"
            "Title: UACE Captions\n"
            "ScriptType: v4.00+\n"
            "WrapStyle: 0\n"
            "ScaledBorderAndShadow: yes\n"
            "YCbCr Matrix: TV.709\n"
            "PlayResX: 1920\n"
            "PlayResY: 1080\n"
            "\n"
        )
    
    def _generate_styles(self) -> str:
        """Generate style definitions."""
        styles = "[V4+ Styles]\n"
        styles += (
            "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, "
            "OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, "
            "ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, "
            "Alignment, MarginL, MarginR, MarginV, Encoding\n"
        )
        styles += self.preset.to_ass_style() + "\n"
        styles += "\n"
        return styles
    
    def _generate_events(self, caption: Caption) -> str:
        """Generate event (dialogue) lines with animations."""
        events = "[Events]\n"
        events += (
            "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, "
            "Effect, Text\n"
        )
        
        for segment in caption.segments:
            event_line = self._create_event(segment)
            events += event_line + "\n"
        
        return events
    
    def _create_event(self, segment: CaptionSegment) -> str:
        """Create a single event line with animation."""
        start = self._format_time(segment.start)
        end = self._format_time(segment.end)
        
        # Apply animation based on style
        if self.preset.effects.animation == AnimationStyle.WORD_POP and segment.has_words():
            text = self._animate_word_pop(segment)
        elif self.preset.effects.animation == AnimationStyle.KARAOKE and segment.has_words():
            text = self._animate_karaoke(segment)
        elif self.preset.effects.animation == AnimationStyle.BOUNCE and segment.has_words():
            text = self._animate_bounce(segment)
        else:
            text = segment.text
        
        # Emphasis words (if auto-emphasis enabled)
        if self.preset.effects.animation == AnimationStyle.WORD_POP:
            text = self._apply_emphasis(text, segment)
        
        return (
            f"Dialogue: 0,{start},{end},{self.preset.name},,0,0,0,,"
            f"{text}"
        )
    
    def _animate_word_pop(self, segment: CaptionSegment) -> str:
        """
        Create word-by-word pop animation.
        
        Uses ASS \\t() transform tags for smooth animations.
        """
        if not segment.has_words():
            return segment.text
        
        words = segment.words
        animated_parts = []
        
        for i, word in enumerate(words):
            # Calculate animation timing relative to segment start
            word_start = (word.start - segment.start) * 1000  # to milliseconds
            anim_duration = self.preset.effects.animation_duration * 1000
            
            # Scale animation: 0 → 1.2 → 1.0
            animated_word = (
                f"{{\\t({word_start:.0f},{word_start + anim_duration * 0.6:.0f},"
                f"\\fscx120\\fscy120)}}"
                f"{{\\t({word_start + anim_duration * 0.6:.0f},"
                f"{word_start + anim_duration:.0f},"
                f"\\fscx100\\fscy100)}}"
                f"{word.text}"
            )
            
            animated_parts.append(animated_word)
        
        return " ".join(animated_parts)
    
    def _animate_karaoke(self, segment: CaptionSegment) -> str:
        """
        Create karaoke-style color-fill animation.
        
        Uses ASS \\k tag for karaoke timing.
        """
        if not segment.has_words():
            return segment.text
        
        karaoke_parts = []
        
        for word in segment.words:
            # Duration in centiseconds (ASS karaoke uses centiseconds)
            duration = int(word.duration * 100)
            
            # Karaoke effect with color change
            karaoke_word = f"{{\\k{duration}}}{word.text}"
            karaoke_parts.append(karaoke_word)
        
        return " ".join(karaoke_parts)
    
    def _animate_bounce(self, segment: CaptionSegment) -> str:
        """
        Create bounce animation for words.
        
        Uses vertical position animation.
        """
        if not segment.has_words():
            return segment.text
        
        words = segment.words
        animated_parts = []
        
        for i, word in enumerate(words):
            word_start = (word.start - segment.start) * 1000
            bounce_duration = self.preset.effects.animation_duration * 1000
            
            # Bounce effect: move up and down
            animated_word = (
                f"{{\\t({word_start:.0f},{word_start + bounce_duration * 0.5:.0f},"
                f"\\frz-5\\fry10)}}"  # Rotate slightly
                f"{{\\t({word_start + bounce_duration * 0.5:.0f},"
                f"{word_start + bounce_duration:.0f},"
                f"\\frz0\\fry0)}}"
                f"{word.text}"
            )
            
            animated_parts.append(animated_word)
        
        return " ".join(animated_parts)
    
    def _apply_emphasis(self, text: str, segment: CaptionSegment) -> str:
        """
        Apply emphasis styling to important words.
        
        Uses color change and scale for emphasis.
        """
        if not segment.emphasis_words or not self.preset.colors.emphasis:
            return text
        
        # For simplicity, emphasize exact matches
        emphasized = text
        for word in segment.emphasis_words:
            emphasis_color = self.preset._color_to_ass(self.preset.colors.emphasis)
            emphasized = emphasized.replace(
                word,
                f"{{\\c{emphasis_color}\\fscx110\\fscy110}}{word}{{\\r}}"
            )
        
        return emphasized
    
    def _format_time(self, seconds: float) -> str:
        """
        Format time for ASS (H:MM:SS.SS).
        
        ASS uses centiseconds for precision.
        """
        td = timedelta(seconds=seconds)
        hours = int(td.total_seconds() // 3600)
        minutes = int((td.total_seconds() % 3600) // 60)
        secs = td.total_seconds() % 60
        
        return f"{hours}:{minutes:02d}:{secs:05.2f}"


class SRTExporter:
    """
    Simple SRT exporter (no animation support).
    
    For basic compatibility.
    """
    
    def export(self, caption: Caption, output_path: str) -> None:
        """Export caption to SRT file."""
        with open(output_path, 'w', encoding='utf-8') as f:
            for i, segment in enumerate(caption.segments, 1):
                f.write(f"{i}\n")
                f.write(f"{self._format_time(segment.start)} --> "
                       f"{self._format_time(segment.end)}\n")
                f.write(f"{segment.text}\n\n")
    
    def _format_time(self, seconds: float) -> str:
        """Format time for SRT (HH:MM:SS,mmm)."""
        td = timedelta(seconds=seconds)
        hours = int(td.total_seconds() // 3600)
        minutes = int((td.total_seconds() % 3600) // 60)
        secs = int(td.total_seconds() % 60)
        millis = int((seconds % 1) * 1000)
        
        return f"{hours:02d}:{minutes:02d}:{secs:02d},{millis:03d}"


class VTTExporter:
    """WebVTT exporter for web use."""
    
    def export(self, caption: Caption, output_path: str) -> None:
        """Export caption to WebVTT file."""
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write("WEBVTT\n\n")
            
            for i, segment in enumerate(caption.segments, 1):
                f.write(f"{self._format_time(segment.start)} --> "
                       f"{self._format_time(segment.end)}\n")
                f.write(f"{segment.text}\n\n")
    
    def _format_time(self, seconds: float) -> str:
        """Format time for WebVTT (HH:MM:SS.mmm)."""
        td = timedelta(seconds=seconds)
        hours = int(td.total_seconds() // 3600)
        minutes = int((td.total_seconds() % 3600) // 60)
        secs = int(td.total_seconds() % 60)
        millis = int((seconds % 1) * 1000)
        
        return f"{hours:02d}:{minutes:02d}:{secs:02d}.{millis:03d}"
