from __future__ import annotations

from typing import Any, Dict, List, Optional, Set


def stringify(value: Any) -> str:
    text = str(value or "").strip()
    return text


def extract_artists(item: Dict[str, Any]) -> List[str]:
    names: List[str] = []
    artists = item.get("artists")
    if isinstance(artists, list):
        for artist in artists:
            if isinstance(artist, dict):
                name = stringify(artist.get("name"))
                if name and name not in names:
                    names.append(name)
    if not names:
        primary = item.get("artist")
        if isinstance(primary, dict):
            name = stringify(primary.get("name"))
            if name:
                names.append(name)
    return names


def build_track_tags(metadata: Dict[str, Any]) -> Set[str]:
    tags: Set[str] = {"tidal"}

    audio_quality = stringify(metadata.get("audioQuality"))
    if audio_quality:
        tags.add(f"quality:{audio_quality.lower()}")

    media_md = metadata.get("mediaMetadata")
    if isinstance(media_md, dict):
        tag_values = media_md.get("tags") or []
        for tag in tag_values:
            if isinstance(tag, str):
                candidate = tag.strip()
                if candidate:
                    tags.add(candidate.lower())

    title_text = stringify(metadata.get("title"))
    if title_text:
        tags.add(f"title:{title_text}")

    artists = extract_artists(metadata)
    for artist in artists:
        artist_clean = stringify(artist)
        if artist_clean:
            tags.add(f"artist:{artist_clean}")

    album_title = ""
    album_obj = metadata.get("album")
    if isinstance(album_obj, dict):
        album_title = stringify(album_obj.get("title"))
    else:
        album_title = stringify(metadata.get("album"))
    if album_title:
        tags.add(f"album:{album_title}")

    track_no_val = metadata.get("trackNumber") or metadata.get("track_number")
    if track_no_val is not None:
        try:
            track_int = int(track_no_val)
            if track_int > 0:
                tags.add(f"track:{track_int}")
        except Exception:
            track_text = stringify(track_no_val)
            if track_text:
                tags.add(f"track:{track_text}")

    return tags


def coerce_duration_seconds(value: Any) -> Optional[int]:
    candidates = [value]
    try:
        if isinstance(value, dict):
            for key in (
                "duration",
                "durationSeconds",
                "duration_sec",
                "duration_ms",
                "durationMillis",
            ):
                if key in value:
                    candidates.append(value.get(key))
    except Exception:
        pass

    for cand in candidates:
        try:
            if cand is None:
                continue
            text = str(cand).strip()
            if text.lower().endswith("ms"):
                text = text[:-2].strip()
            num = float(text)
            if num <= 0:
                continue
            if num > 10_000:
                num = num / 1000.0
            return int(round(num))
        except Exception:
            continue
    return None
