"""Media-Datei-Modell mit Stream-Informationen"""
import os
import math
from dataclasses import dataclass, field
from typing import Optional


@dataclass
class VideoStream:
    """Einzelner Video-Stream"""
    index: int
    codec_name: str
    width: int = 0
    height: int = 0
    pix_fmt: str = ""
    frame_rate: float = 0.0
    level: Optional[int] = None
    bit_rate: Optional[int] = None

    @property
    def is_10bit(self) -> bool:
        """Erkennt ob der Stream 10-Bit ist"""
        return "10" in self.pix_fmt or "p010" in self.pix_fmt

    @property
    def resolution(self) -> str:
        return f"{self.width}x{self.height}"


@dataclass
class AudioStream:
    """Einzelner Audio-Stream"""
    index: int
    codec_name: str
    channels: int = 2
    sample_rate: int = 48000
    language: Optional[str] = None
    bit_rate: Optional[int] = None

    @property
    def channel_layout(self) -> str:
        """Menschenlesbares Kanal-Layout"""
        layouts = {1: "Mono", 2: "Stereo", 3: "2.1", 6: "5.1", 8: "7.1"}
        return layouts.get(self.channels, f"{self.channels}ch")


@dataclass
class SubtitleStream:
    """Einzelner Untertitel-Stream"""
    index: int
    codec_name: str
    language: Optional[str] = None


@dataclass
class MediaFile:
    """Analysierte Mediendatei mit allen Stream-Informationen"""
    source_path: str
    source_dir: str = field(init=False)
    source_filename: str = field(init=False)
    source_extension: str = field(init=False)
    source_size_bytes: int = 0
    source_duration_sec: float = 0.0
    source_bitrate: int = 0

    video_streams: list[VideoStream] = field(default_factory=list)
    audio_streams: list[AudioStream] = field(default_factory=list)
    subtitle_streams: list[SubtitleStream] = field(default_factory=list)

    def __post_init__(self) -> None:
        self.source_dir = os.path.dirname(self.source_path)
        self.source_filename = os.path.basename(self.source_path)
        self.source_extension = os.path.splitext(self.source_filename)[1].lower()

    @property
    def frame_rate(self) -> float:
        """Framerate des ersten Video-Streams"""
        if self.video_streams:
            return self.video_streams[0].frame_rate
        return 0.0

    @property
    def total_frames(self) -> int:
        """Gesamtanzahl Frames"""
        return int(self.frame_rate * self.source_duration_sec)

    @property
    def is_10bit(self) -> bool:
        """Prueft ob der erste Video-Stream 10-Bit ist"""
        if self.video_streams:
            return self.video_streams[0].is_10bit
        return False

    @property
    def source_size_human(self) -> tuple[float, str]:
        """Menschenlesbare Groesse"""
        return self.format_size(self.source_size_bytes)

    def to_dict(self) -> dict:
        """Serialisiert fuer WebSocket/API"""
        size = self.source_size_human
        return {
            "source_path": self.source_path,
            "source_dir": self.source_dir,
            "source_filename": self.source_filename,
            "source_extension": self.source_extension,
            "source_size": [size[0], size[1]],
            "source_duration": self.source_duration_sec,
            "source_duration_human": self.format_time(self.source_duration_sec),
            "source_frame_rate": self.frame_rate,
            "source_frames_total": self.total_frames,
            "video_streams": len(self.video_streams),
            "audio_streams": [
                {"index": a.index, "codec": a.codec_name,
                 "channels": a.channels, "layout": a.channel_layout,
                 "language": a.language}
                for a in self.audio_streams
            ],
            "subtitle_streams": [
                {"index": s.index, "codec": s.codec_name,
                 "language": s.language}
                for s in self.subtitle_streams
            ],
        }

    @staticmethod
    def format_size(size_bytes: int) -> tuple[float, str]:
        """Konvertiert Bytes in menschenlesbare Groesse"""
        units = ["B", "KiB", "MiB", "GiB", "TiB"]
        size = float(size_bytes)
        unit_idx = 0
        while size >= 1024.0 and unit_idx < len(units) - 1:
            size /= 1024.0
            unit_idx += 1
        return round(size, 1), units[unit_idx]

    @staticmethod
    def format_time(seconds: float) -> str:
        """Formatiert Sekunden in lesbares Format"""
        if seconds <= 0:
            return "0 Min"
        days = int(seconds // 86400)
        seconds %= 86400
        hours = int(seconds // 3600)
        seconds %= 3600
        minutes = math.ceil(seconds / 60)

        parts = []
        if days:
            parts.append(f"{days} Tage")
        if hours:
            parts.append(f"{hours} Std")
        if minutes:
            parts.append(f"{minutes} Min")
        return " ".join(parts) if parts else "< 1 Min"

    @staticmethod
    def time_to_seconds(time_str: str) -> float:
        """Konvertiert HH:MM:SS oder Sekunden-String in float"""
        parts = time_str.split(":")
        if len(parts) == 1:
            return float(parts[0])
        if len(parts) == 3:
            h, m, s = map(float, parts)
            return h * 3600 + m * 60 + s
        return 0.0
