"""Transcription stage: extract word-level timestamps from video audio."""

import json
import subprocess
from dataclasses import dataclass
from pathlib import Path

from .cache import resolve_with_cache
from .errors import GnommoError
from typing import Optional


@dataclass
class TranscribedWord:
    """A word with its timestamp from transcription."""

    word: str
    start: float
    end: float


class TranscriptionError(GnommoError):
    """Error during transcription."""

    pass


def transcribe_video(video_path: Path, model: str = "base") -> list[TranscribedWord]:
    """
    Transcribe video audio using Whisper and return word-level timestamps.

    Args:
        video_path: Path to video file
        model: Whisper model size (tiny, base, small, medium, large)

    Returns:
        List of TranscribedWord with timestamps
    """
    try:
        import whisper
    except ImportError:
        raise TranscriptionError(
            "Whisper not installed. Run: pip install openai-whisper"
        )

    if not video_path.exists():
        raise TranscriptionError(f"Video file not found: {video_path}")

    print(f"  Loading Whisper model '{model}'...")
    whisper_model = whisper.load_model(model)

    print(f"  Transcribing {video_path.name}...")
    result = whisper_model.transcribe(
        str(video_path),
        word_timestamps=True,
        verbose=False,
    )

    # Extract word-level timestamps
    words: list[TranscribedWord] = []

    for segment in result.get("segments", []):
        for word_info in segment.get("words", []):
            words.append(
                TranscribedWord(
                    word=word_info["word"].strip(),
                    start=word_info["start"],
                    end=word_info["end"],
                )
            )

    return words


def save_transcript(words: list[TranscribedWord], output_path: Path) -> None:
    """Save transcribed words to a JSON file."""
    data = [{"word": w.word, "start": w.start, "end": w.end} for w in words]

    with open(output_path, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2)


def load_transcript(
    transcript_path: Path, project_path: Optional[Path] = None
) -> list[TranscribedWord]:
    """Load transcribed words from a JSON file.

    Args:
        transcript_path: Path to the transcript JSON file
        project_path: Optional project path for cache fallback
    """
    # Try cache fallback if project_path provided
    if project_path:
        transcript_path, _ = resolve_with_cache(transcript_path, project_path)

    if not transcript_path.exists():
        raise TranscriptionError(f"Transcript file not found: {transcript_path}")

    with open(transcript_path, "r", encoding="utf-8") as f:
        data = json.load(f)

    return [
        TranscribedWord(word=w["word"], start=w["start"], end=w["end"]) for w in data
    ]


def _format_srt_timestamp(seconds: float) -> str:
    """Format seconds as SRT timestamp: HH:MM:SS,mmm"""
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    secs = int(seconds % 60)
    millis = int((seconds % 1) * 1000)
    return f"{hours:02d}:{minutes:02d}:{secs:02d},{millis:03d}"


def words_to_srt(
    words: list[TranscribedWord],
    max_words_per_line: int = 10,
    max_duration: float = 5.0,
    gap_threshold: float = 1.0,
) -> str:
    """
    Convert word-level timestamps to SRT caption format.

    Groups words into readable caption segments based on:
    - Maximum words per line (default: 10)
    - Maximum segment duration (default: 5 seconds)
    - Natural gaps between words (default: 1 second pause triggers new segment)

    Args:
        words: List of TranscribedWord with timestamps
        max_words_per_line: Maximum words before splitting to new segment
        max_duration: Maximum duration of a single caption segment
        gap_threshold: Pause duration that triggers a new segment

    Returns:
        SRT formatted string ready for YouTube upload
    """
    if not words:
        return ""

    segments: list[tuple[float, float, str]] = []  # (start, end, text)
    current_words: list[str] = []
    segment_start: float = words[0].start
    segment_end: float = words[0].end

    for i, word in enumerate(words):
        # Check if we should start a new segment
        start_new_segment = False

        # Gap between words
        if current_words and (word.start - segment_end) > gap_threshold:
            start_new_segment = True

        # Too many words
        if len(current_words) >= max_words_per_line:
            start_new_segment = True

        # Segment too long
        if current_words and (word.end - segment_start) > max_duration:
            start_new_segment = True

        if start_new_segment and current_words:
            # Save current segment
            text = " ".join(current_words)
            segments.append((segment_start, segment_end, text))
            # Start new segment
            current_words = []
            segment_start = word.start

        current_words.append(word.word)
        segment_end = word.end

    # Don't forget the last segment
    if current_words:
        text = " ".join(current_words)
        segments.append((segment_start, segment_end, text))

    # Format as SRT
    srt_lines = []
    for idx, (start, end, text) in enumerate(segments, 1):
        srt_lines.append(str(idx))
        srt_lines.append(
            f"{_format_srt_timestamp(start)} --> {_format_srt_timestamp(end)}"
        )
        srt_lines.append(text)
        srt_lines.append("")  # Blank line between entries

    return "\n".join(srt_lines)
