"""Bildformate des Wi-Fi-Display-Standards und die Auswahl daraus.

Der Fernseher meldet in einer Bitmaske, welche Auflösungen er beherrscht.
Wir suchen die beste heraus, die beide Seiten können, und melden genau diese
eine zurück.
"""

from dataclasses import dataclass
from typing import List, Optional


@dataclass(frozen=True)
class VideoFormat:
    cea_bit: int
    width: int
    height: int
    fps: int

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


# CEA-Tabelle des Standards; die Position entspricht dem Bit in der Maske.
CEA = [
    VideoFormat(0, 640, 480, 60),
    VideoFormat(1, 720, 480, 60),
    VideoFormat(2, 720, 480, 60),    # interlaced
    VideoFormat(3, 720, 576, 50),
    VideoFormat(4, 720, 576, 50),    # interlaced
    VideoFormat(5, 1280, 720, 30),
    VideoFormat(6, 1280, 720, 60),
    VideoFormat(7, 1920, 1080, 30),
    VideoFormat(8, 1920, 1080, 60),
    VideoFormat(9, 1920, 1080, 60),  # interlaced
    VideoFormat(10, 1280, 720, 25),
    VideoFormat(11, 1280, 720, 50),
    VideoFormat(12, 1920, 1080, 25),
    VideoFormat(13, 1920, 1080, 50),
    VideoFormat(14, 1920, 1080, 50), # interlaced
    VideoFormat(15, 1280, 720, 24),
    VideoFormat(16, 1920, 1080, 24),
]

INTERLACED = {2, 4, 9, 14}

# Wunschreihenfolge: flüssig und scharf, ohne zu übertreiben.
PREFERENCE = [5, 7, 6, 11, 13, 10, 12, 15, 16, 8, 0, 1, 3]


@dataclass(frozen=True)
class SinkCapability:
    profile: int
    level: int
    cea_mask: int
    vesa_mask: int
    hh_mask: int


def parse_video_formats(value: str) -> List[SinkCapability]:
    """Zerlegt den Wert von wfd_video_formats.

    Aufbau: native, preferred-display-mode, dann je Codec elf Felder
    (profile, level, CEA, VESA, HH, latency, min-slice, slice-enc,
    frame-rate-control, max-hres, max-vres).
    """
    parts = value.strip().split()
    if len(parts) < 3:
        return []
    result = []
    i = 2  # native und preferred-display-mode überspringen
    while i + 4 < len(parts):
        try:
            capability = SinkCapability(
                profile=int(parts[i], 16),
                level=int(parts[i + 1], 16),
                cea_mask=int(parts[i + 2], 16),
                vesa_mask=int(parts[i + 3], 16),
                hh_mask=int(parts[i + 4], 16),
            )
        except ValueError:
            break
        result.append(capability)
        i += 11
    return result


def choose(capabilities: List[SinkCapability], max_height: int = 1080) -> Optional[VideoFormat]:
    """Bestes gemeinsames Format, oder None wenn es keines gibt."""
    mask = 0
    for capability in capabilities:
        mask |= capability.cea_mask
    for bit in PREFERENCE:
        if bit in INTERLACED or not (mask & (1 << bit)):
            continue
        candidate = CEA[bit]
        if candidate.height > max_height:
            continue
        return candidate
    return None


def build_selection(fmt: VideoFormat, profile: int, level: int) -> str:
    """Antwortwert mit genau einem gesetzten Bit - damit der Fernseher weiß,
    was tatsächlich kommt."""
    cea = 1 << fmt.cea_bit
    return (
        f"{0:02X} {0:02X} {profile:02X} {level:02X} "
        f"{cea:08X} {0:08X} {0:08X} {0:02X} {0:04X} {0:04X} {0:02X} none none"
    )


def parse_rtp_port(value: Optional[str]) -> int:
    """Liest aus wfd_client_rtp_ports den Port, auf dem der Fernseher lauscht."""
    if not value:
        return 0
    for part in value.strip().split():
        if part.isdigit():
            port = int(part)
            if 1 <= port <= 65535:
                return port
    return 0
