"""
Manual account field definitions per smile.one merchant (by URL slug).

Replaces flaky Playwright first-screen scraping for /api/account-fields so the
checkout form always shows. Keys (game_id, server_id, email, …) are filled by
order_automation using input[name=…] and common aliases on BR pages.
"""

from __future__ import annotations

import json
from pathlib import Path
from urllib.parse import urlparse

_DATA_FILE = Path(__file__).resolve().parent / "smile_one_data.json"
_SCRAPED_FILE = Path(__file__).resolve().parent / "manual_account_fields_scraped.json"


def _scraped_fields_by_slug() -> dict[str, list[dict]]:
    """Live DOM snapshot from tools/snapshot_account_fields.py (optional)."""
    if not _SCRAPED_FILE.is_file():
        return {}
    try:
        data = json.loads(_SCRAPED_FILE.read_text(encoding="utf-8"))
        return data.get("by_slug") or {}
    except Exception:
        return {}


# Gift / entertainment / vouchers — usually email + optional region (not in-game UID)
_ENTERTAINMENT_SLUGS = frozenset(
    {
        "avatar",
        "airbnb",
        "uber",
        "nintendo",
        "playstation",
        "blizzard",
        "microsoftoffice",
        "mcafee",
        "microsoftcsv",
        "microsoftminecoins",
        "tinder",
        "tindercode",
        "tindertopup",
    }
)

# Phone top-up
_PHONE_SLUGS = frozenset({"telephone"})


def _two_game_fields(
    uid_label: str = "User / Player ID",
    uid_ph: str = "In-game ID from your profile",
    server_label: str = "Server / Zone ID",
    server_ph: str = "Server, zone, or world ID",
    server_required: bool = True,
) -> list[dict]:
    return [
        {
            "key": "game_id",
            "label": uid_label,
            "type": "text",
            "placeholder": uid_ph,
            "required": True,
        },
        {
            "key": "server_id",
            "label": server_label,
            "type": "text",
            "placeholder": server_ph,
            "required": server_required,
        },
    ]


def _entertainment_fields() -> list[dict]:
    return [
        {
            "key": "email",
            "label": "Email",
            "type": "text",
            "placeholder": "Recipient email (for delivery)",
            "required": True,
        },
        {
            "key": "region",
            "label": "Region / Country",
            "type": "text",
            "placeholder": "If the product asks for region (e.g. US, BR)",
            "required": False,
        },
    ]


def _phone_fields() -> list[dict]:
    return [
        {
            "key": "phone_number",
            "label": "Phone number",
            "type": "tel",
            "placeholder": "Number to recharge (with country code if required)",
            "required": True,
        },
    ]


# Per-slug label tweaks (optional) — keys must stay game_id / server_id for automation
_SLUG_LABELS: dict[str, tuple[str, str, str, str]] = {
    "mobilelegends": ("Game ID", "From MLBB profile", "Server / Zone ID", "Zone ID (numbers)"),
    "honkai": ("UID", "Honkai: Star Rail UID", "Server", "Server name or code"),
    "wherewindsmeet": ("Player ID", "Where Winds Meet player ID", "Server / World", "Server or world ID"),
    "pubgmobile": ("Player ID", "PUBG Mobile character ID", "Server ID", "Server or region ID"),
    "freefire": ("Player ID", "Free Fire player ID", "Server", "Server / region"),
    "hok": ("Player ID", "Honor of Kings player ID", "Server / Zone", "Zone ID"),
    "identityv": ("User ID", "Identity V user ID", "Server", "Server / channel"),
    "ragnarokm": ("Character", "Character / account identifier", "Server", "Server name or number"),
    "ragnarokmclassic": ("Character", "Character / account identifier", "Server", "Server name or number"),
    "loveanddeepspace": ("Player ID", "Love and Deepspace ID", "Server", "Server / region"),
    "shiningnikki": ("Player ID", "Shining Nikki ID", "Server", "Server / region"),
    "lovenikki": ("Player ID", "Love Nikki ID", "Server", "Server / region"),
    "pathtonowhere": ("Chief ID", "Path to Nowhere chief ID", "Server", "Server / region"),
    "ddtank": ("Player ID", "DDTank player ID", "Server", "Server number"),
    "ddtankorigin": ("Player ID", "DDTank Origin player ID", "Server", "Server number"),
    "arenabreakout": ("Player ID", "Arena Breakout player ID", "Server", "Server / region"),
    "bloodstrike": ("Player ID", "Blood Strike player ID", "Server", "Server / region"),
    "sausageman": ("Player ID", "Sausage Man player ID", "Server", "Server / region"),
    "sweetdance": ("Player ID", "Sweet Dance player ID", "Server", "Server / region"),
    "kingofavalon": ("Lord ID", "King of Avalon lord ID", "Kingdom", "Kingdom / server"),
    "islandking": ("Player ID", "Island King player ID", "Server", "Server / region"),
    "bombme": ("Player ID", "Bomb Me player ID", "Server", "Server / region"),
    "watcherofrealms": ("Player ID", "Watcher of Realms player ID", "Server", "Server / region"),
    "gemadodestino": ("Player ID", "Player ID", "Server", "Server / region"),
    "echocalypsescarletcovenant": ("Player ID", "Player ID", "Server", "Server / region"),
    "nightoffullmoon": ("Player ID", "Player ID", "Server", "Server / region"),
    "conquer": ("Player ID", "Conquer player ID", "Server", "Server / region"),
    "naruto": ("Player ID", "NARUTO H5 player ID", "Server", "Server / region"),
    "saintseiyalegendofjustice": ("Player ID", "Player ID", "Server", "Server / region"),
    "saintseiyaawakening": ("Player ID", "Player ID", "Server", "Server / region"),
    "aplus": ("Player ID", "Street Fighter: Duel player ID", "Server", "Server / region"),
    "twd": ("Player ID", "TWD Survivors player ID", "Server", "Server / region"),
    "supersus": ("Player ID", "Super Sus player ID", "Server", "Server / region"),
    "lordsmobilekingdomwars": ("Lord ID", "Lords Mobile lord ID", "Kingdom", "Kingdom / server"),
    "doomsdaylastsurvivors": ("Player ID", "Player ID", "Server", "Server / region"),
    "vikingrise": ("Player ID", "Viking Rise player ID", "Server", "Server / region"),
    "racingmaster": ("Player ID", "Racing Master player ID", "Server", "Server / region"),
    "wartuneultra": ("Player ID", "Wartune Ultra player ID", "Server", "Server / region"),
    "magicchessgogo": ("Player ID", "Magic Chess player ID", "Server", "Server / region"),
    "dunkcitydynasty": ("Player ID", "Dunk City Dynasty player ID", "Server", "Server / region"),
    "terabox": ("Account / Email", "TeraBox account or email", "Note", "Extra info if needed"),
    "bigocode": ("Bigo ID", "Bigo live ID", "Optional", "Leave blank if not asked",),
    "bigo": ("Bigo ID", "Bigo live ID", "Optional", "Extra if required",),
    "lamour": ("Account ID", "OmniChat / Lamour account", "Server", "Region / server if any",),
    "hago": ("Player ID", "Hago player ID", "Server", "Server / region",),
    "heyy": ("User ID", "Heyy user ID", "Server", "Server / region",),
}


def _normalize_snapshot_fields(slug: str, fields: list[dict]) -> list[dict]:
    """Human-friendly labels; keep keys from smile.one (email, uid, sid, …) for order_automation."""
    out: list[dict] = []
    for f in fields:
        if not f.get("key"):
            continue
        fc = dict(f)
        k = (fc.get("key") or "").strip().lower()
        lbl = (fc.get("label") or "").strip()
        if k == "sid" and fc.get("type") == "select":
            fc["label"] = "Server / region" if lbl.lower() in ("", "sid") else lbl
        elif k == "uid":
            fc["label"] = "User ID" if lbl.lower() in ("", "uid") else lbl
            if (fc.get("type") or "").lower() == "tel":
                fc["type"] = "text"
        elif k == "email":
            fc["type"] = "email"
            fc["required"] = True
        out.append(fc)
    return out


def extract_merchant_slug(url: str) -> str | None:
    """Last meaningful segment for /merchant/... or entertainment/pay/..."""
    p = urlparse((url or "").strip())
    parts = [x for x in p.path.strip("/").split("/") if x]
    for i, seg in enumerate(parts):
        if seg == "merchant" and i + 1 < len(parts):
            if parts[i + 1] == "game" and i + 2 < len(parts):
                return parts[i + 2].lower()
            return parts[i + 1].lower()
        if seg == "pay" and i + 1 < len(parts):
            return parts[i + 1].lower()
    return None


def fields_for_slug(slug: str | None) -> list[dict] | None:
    """
    Prefer manual_account_fields_scraped.json (Playwright capture from real smile.one DOM,
    tools/snapshot_account_fields.py). That matches what the storefront actually asks
    (e.g. PUBG/HoK = email only; Where Winds Meet = sid select + uid).
    If JSON is missing, fall back to _SLUG_LABELS / generic two-field.
    """
    if not slug:
        return None
    s = slug.lower()
    scraped = _scraped_fields_by_slug()
    raw = scraped.get(s)

    if raw:
        return _normalize_snapshot_fields(s, list(raw))

    if s in _PHONE_SLUGS:
        return _phone_fields()

    if s in _ENTERTAINMENT_SLUGS:
        return _entertainment_fields()

    if s in _SLUG_LABELS:
        u, up, sv, sp = _SLUG_LABELS[s]
        req = s not in ("bigocode", "bigo", "terabox")
        return _two_game_fields(u, up, sv, sp, server_required=req)

    return _two_game_fields()


def get_manual_fields_for_url(url: str) -> list[dict]:
    """Return manual field list for this merchant URL (always non-empty for typical smile.one paths)."""
    slug = extract_merchant_slug(url)
    if not slug:
        return _two_game_fields(
            "User / Player ID",
            "In-game ID from your profile",
            "Server / Zone",
            "Server, zone, or world",
        )
    return fields_for_slug(slug)


def all_catalog_slugs() -> list[str]:
    """Slugs from smile_one_data.json (for tests / admin)."""
    if not _DATA_FILE.is_file():
        return []
    try:
        data = json.loads(_DATA_FILE.read_text(encoding="utf-8"))
    except Exception:
        return []
    out: list[str] = []
    for m in data.get("merchants") or []:
        u = (m.get("url") or "").strip()
        s = extract_merchant_slug(u)
        if s and s not in out:
            out.append(s)
    return sorted(out)
