import json
from logging import getLogger
from typing import Any, overload

from autosubs.core.builder import create_dict_from_subtitles
from autosubs.core.styler import AssStyler
from autosubs.models.subtitles import Subtitles
from autosubs.models.subtitles.ass import AssSubtitles, AssSubtitleSegment

logger = getLogger(__name__)
ASS_NEWLINE = r"\N"


def format_srt_timestamp(seconds: float) -> str:
    """Formats srt timestamps."""
    hrs = int(seconds // 3600)
    mins = int((seconds % 3600) // 60)
    secs = int(seconds % 60)
    millis = int(round((seconds - int(seconds)) * 1000))
    return f"{hrs:02}:{mins:02}:{secs:02},{millis:03}"


def format_vtt_timestamp(seconds: float) -> str:
    """Formats vtt timestamps."""
    hrs = int(seconds // 3600)
    mins = int((seconds % 3600) // 60)
    secs = int(seconds % 60)
    millis = int(round((seconds - int(seconds)) * 1000))
    return f"{hrs:02}:{mins:02}:{secs:02}.{millis:03}"


def format_ass_timestamp(seconds: float) -> str:
    """Formats ass timestamps."""
    h = int(seconds // 3600)
    m = int((seconds % 3600) // 60)
    s = int(seconds % 60)
    cs = int((seconds - s - m * 60 - h * 3600) * 100 + 0.5)
    return f"{h}:{m:02}:{s:02}.{cs:02}"


def _reconstruct_dialogue_text(segment: AssSubtitleSegment) -> str:
    parts: list[str] = []
    for word in segment.words:
        tag_string = "".join(style.ass_tag for style in word.styles)
        text = word.text.replace("\n", r"\N")
        parts.append(f"{tag_string}{text}")
    return "".join(parts)


def _format_ass_number(value: Any) -> str:
    if isinstance(value, float) and value.is_integer():
        return str(int(value))
    if isinstance(value, bool):
        return "-1" if value else "0"
    return str(value)


@overload
def to_ass(subtitles: AssSubtitles) -> str: ...


@overload
def to_ass(subtitles: Subtitles, styler_engine: AssStyler) -> str: ...


def to_ass(subtitles: Subtitles, styler_engine: AssStyler | None = None) -> str:
    """Generate the content for an ASS subtitle file."""
    if isinstance(subtitles, AssSubtitles):
        logger.info("Regenerating ASS file from AssSubtitles object...")
        lines: list[str] = []

        lines.append("[Script Info]")
        lines.extend(f"{key}: {value}" for key, value in sorted(subtitles.script_info.items()))
        lines.append("")

        lines.append("[V4+ Styles]")
        if styler_engine and styler_engine.config.styles:
            config = styler_engine.config
            style_format_keys = list(config.styles[0].keys())
            lines.append(f"Format: {', '.join(style_format_keys)}")
            for style_dict in config.styles:
                values = [_format_ass_number(style_dict.get(key, "")) for key in style_format_keys]
                lines.append(f"Style: {','.join(values)}")
        else:
            logger.warning("No AssStyler or styles provided; [V4+ Styles] section will be empty.")
        lines.append("")

        lines.append("[Events]")
        if subtitles.segments:
            events_format_keys = subtitles.events_format_keys
            if not events_format_keys:
                events_format_keys = [
                    "Layer",
                    "Start",
                    "End",
                    "Style",
                    "Name",
                    "MarginL",
                    "MarginR",
                    "MarginV",
                    "Effect",
                    "Text",
                ]
            lines.append(f"Format: {', '.join(events_format_keys)}")

            for segment in subtitles.segments:
                dialogue_data = {
                    "Layer": segment.layer,
                    "Start": format_ass_timestamp(segment.start),
                    "End": format_ass_timestamp(segment.end),
                    "Style": segment.style_name,
                    "Name": segment.actor_name,
                    "MarginL": segment.margin_l,
                    "MarginR": segment.margin_r,
                    "MarginV": segment.margin_v,
                    "Effect": segment.effect,
                    "Text": _reconstruct_dialogue_text(segment),
                }
                values = [str(dialogue_data.get(key, "")) for key in events_format_keys]
                lines.append(f"Dialogue: {','.join(values)}")

        return "\n".join(lines) + "\n"

    if not styler_engine:
        raise ValueError("AssStyler is required to generate an ASS file from scratch.")

    logger.info("Generating ASS file using the AssStyler.")
    config = styler_engine.config
    lines = ["[Script Info]"]
    lines.extend(f"{key}: {value}" for key, value in config.script_info.items())
    lines.append("\n[V4+ Styles]")
    if config.styles:
        style_format_keys = list(config.styles[0].keys())
        lines.append(f"Format: {', '.join(style_format_keys)}")
        for style_dict in config.styles:
            lines.append(f"Style: {','.join(_format_ass_number(style_dict.get(key, '')) for key in style_format_keys)}")
    lines.append("\n[Events]")
    lines.append("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text")

    default_style = config.styles[0].get("Name", "Default") if config.styles else "Default"
    for seg in subtitles.segments:
        result = styler_engine.process_segment(seg, default_style)
        start, end = format_ass_timestamp(seg.start), format_ass_timestamp(seg.end)
        # We can assume it's AssStylingResult because we are in to_ass
        lines.append(f"Dialogue: 0,{start},{end},{result.style_name},,0,0,0,,{result.text}")
    return "\n".join(lines) + "\n"


def to_srt(subtitles: Subtitles) -> str:
    """Generate the content for an SRT subtitle file."""
    logger.info("Generating subtitles in SRT format...")
    srt_blocks: list[str] = []
    for i, segment in enumerate(subtitles.segments, 1):
        start_time = format_srt_timestamp(segment.start)
        end_time = format_srt_timestamp(segment.end)
        srt_blocks.append(f"{i}\n{start_time} --> {end_time}\n{segment.text}")
    return "\n\n".join(srt_blocks) + "\n\n" if srt_blocks else ""


def to_vtt(subtitles: Subtitles) -> str:
    """Generate the content for a VTT subtitle file."""
    logger.info("Generating subtitles in VTT format...")
    if not subtitles.segments:
        return "WEBVTT\n"
    vtt_blocks: list[str] = ["WEBVTT"]
    for segment in subtitles.segments:
        start_time = format_vtt_timestamp(segment.start)
        end_time = format_vtt_timestamp(segment.end)
        vtt_blocks.append(f"{start_time} --> {end_time}\n{segment.text}")
    return "\n\n".join(vtt_blocks) + "\n\n"


def to_json(subtitles: Subtitles) -> str:
    """Generate a JSON representation of the subtitles."""
    logger.info("Generating subtitles in JSON format...")
    return json.dumps(create_dict_from_subtitles(subtitles), indent=4, ensure_ascii=False)
