"""Danbooru-style outfit tags with color enrichment for stable SD prompts."""

import json
import re

COLOR_TOKENS = frozenset({
    "white", "black", "red", "blue", "green", "yellow", "pink", "purple",
    "orange", "brown", "gray", "grey", "silver", "gold", "beige", "navy",
    "blonde", "dark", "light", "cyan", "teal", "maroon", "crimson",
})

# garment substring -> default color when tag has no color word
_GARMENT_DEFAULT_COLOR: list[tuple[str, str]] = [
    ("championship_belt", "gold"),
    ("belt_collar", "gold"),
    ("belt", "brown"),
    ("sports_shorts", "black"),
    ("shorts", "black"),
    ("torn_tank_top", "white"),
    ("tank_top", "white"),
    ("crop_top", "white"),
    ("t_shirt", "white"),
    ("shirt", "white"),
    ("dress", "black"),
    ("skirt", "black"),
    ("jeans", "blue"),
    ("pants", "black"),
    ("hoodie", "gray"),
    ("jacket", "black"),
    ("ribbon", "red"),
    ("collar", "black"),
    ("boots", "black"),
    ("socks", "white"),
]


def _clean_tag(raw: str) -> str:
    t = (raw or "").strip().lower()
    t = re.sub(r"[^\w]+", "_", t)
    t = re.sub(r"_+", "_", t).strip("_")
    return t


def tag_has_color(tag: str) -> bool:
    parts = tag.lower().split("_")
    return any(p in COLOR_TOKENS for p in parts)


def enrich_outfit_tag(tag: str) -> str:
    """Add a color prefix when the tag names clothing but omits color."""
    t = _clean_tag(tag)
    if not t or tag_has_color(t):
        return t
    for needle, color in _GARMENT_DEFAULT_COLOR:
        if needle in t:
            return f"{color}_{t}"
    return t


def normalize_outfit_list(raw: list | None) -> list[str]:
    out: list[str] = []
    seen: set[str] = set()
    if not isinstance(raw, list):
        return out
    for item in raw:
        if isinstance(item, str):
            t = enrich_outfit_tag(item)
        elif isinstance(item, dict):
            label = (item.get("tag") or item.get("label") or "").strip()
            color = (item.get("color") or "").strip().lower()
            base = _clean_tag(label)
            if not base:
                continue
            t = f"{color}_{base}" if color and not tag_has_color(base) else enrich_outfit_tag(base)
        else:
            continue
        if t and t not in seen:
            seen.add(t)
            out.append(t)
    return out


def outfit_list_to_json(tags: list[str]) -> str:
    return json.dumps(normalize_outfit_list(tags), ensure_ascii=False)


def parse_and_normalize_outfit_json(raw: str | None) -> str:
    try:
        data = json.loads(raw or "[]")
    except (json.JSONDecodeError, TypeError):
        data = []
    if isinstance(data, str):
        data = [x.strip() for x in data.split(",") if x.strip()]
    return outfit_list_to_json(data if isinstance(data, list) else [])
