"""Mechanical tagging: derive mode/duration_s/resolution from a Probe.

Honors the cover-art guard (spec §5.1): an embedded album-art image in an audio
file shows up as a video stream with disposition.attached_pic == 1; it must NOT
make the file 'av'.
"""

from __future__ import annotations

import math
from dataclasses import dataclass

from tools.probe import Probe


@dataclass
class Tags:
    mode: str
    duration_s: int
    resolution: str


def _is_real_video(stream) -> bool:
    if stream.get("codec_type") != "video":
        return False
    return stream.get("disposition", {}).get("attached_pic", 0) != 1


def _parse_duration(value) -> float:
    try:
        return float(value)
    except (TypeError, ValueError):
        return 0.0


def derive_tags(probe: Probe) -> Tags:
    real_video = [s for s in probe.streams if _is_real_video(s)]
    has_audio = any(s.get("codec_type") == "audio" for s in probe.streams)

    if real_video and has_audio:
        mode = "av"
    elif real_video:
        mode = "video"
    else:
        mode = "audio"

    resolution = ""
    if real_video:
        v = real_video[0]
        w, h = v.get("width"), v.get("height")
        if w and h:
            resolution = f"{w}x{h}"

    if "duration" in probe.format:
        seconds = _parse_duration(probe.format.get("duration"))
    else:
        seconds = max(
            (_parse_duration(s.get("duration")) for s in probe.streams),
            default=0.0,
        )

    # Round half up (math.floor(x + 0.5)) rather than Python's banker's
    # rounding, so a 12.5s clip becomes 13s as the spec intends.
    duration_s = max(0, math.floor(seconds + 0.5))
    return Tags(mode=mode, duration_s=duration_s, resolution=resolution)
