"""
Blizzard SC2 API client for ranked MMR and ladder data.

Requires a Battle.net API key (free at https://develop.battle.net).
Credentials stored in config.toml as blizzard.client_id and blizzard.client_secret.
"""
import time
from typing import Optional
import urllib.request
import urllib.parse
import json
import base64

from .config import load_config

# Region ID -> API base URL
REGION_HOSTS = {
    1: "us.api.blizzard.com",
    2: "eu.api.blizzard.com",
    3: "kr.api.blizzard.com",
}

REGION_NAMES = {
    "us": 1, "na": 1,
    "eu": 2,
    "kr": 3, "tw": 3, "asia": 3,
}

# Token cache
_token_cache = {"token": None, "expires_at": 0}


def get_credentials() -> tuple:
    """Get Blizzard API credentials from config.

    Returns:
        (client_id, client_secret) or (None, None) if not configured
    """
    config = load_config()
    blizzard = config.get("blizzard", {})
    client_id = blizzard.get("client_id", "")
    client_secret = blizzard.get("client_secret", "")
    if client_id and client_secret:
        return client_id, client_secret
    return None, None


def is_configured() -> bool:
    """Check if Blizzard API credentials are set."""
    client_id, client_secret = get_credentials()
    return bool(client_id and client_secret)


def _get_token() -> Optional[str]:
    """Get OAuth2 token using client credentials flow. Cached for 23 hours."""
    global _token_cache

    if _token_cache["token"] and time.time() < _token_cache["expires_at"]:
        return _token_cache["token"]

    client_id, client_secret = get_credentials()
    if not client_id:
        return None

    try:
        credentials = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()
        data = urllib.parse.urlencode({"grant_type": "client_credentials"}).encode()
        req = urllib.request.Request(
            "https://oauth.battle.net/token",
            data=data,
            headers={"Authorization": f"Basic {credentials}"},
        )
        with urllib.request.urlopen(req, timeout=10) as resp:
            result = json.loads(resp.read())

        _token_cache["token"] = result["access_token"]
        # Expire 1 hour early to be safe
        _token_cache["expires_at"] = time.time() + result.get("expires_in", 86400) - 3600
        return _token_cache["token"]
    except Exception:
        return None


def _api_get(url: str) -> Optional[dict]:
    """Make an authenticated GET request to the Blizzard API."""
    token = _get_token()
    if not token:
        return None

    try:
        separator = "&" if "?" in url else "?"
        full_url = f"{url}{separator}access_token={token}"
        req = urllib.request.Request(full_url)
        with urllib.request.urlopen(req, timeout=10) as resp:
            return json.loads(resp.read())
    except Exception:
        return None


def get_region_id(region_str: str) -> int:
    """Convert region string to Blizzard region ID."""
    return REGION_NAMES.get(region_str.lower(), 2)


def get_ladder_summary(region_id: int, realm_id: int, profile_id: int) -> Optional[dict]:
    """Get ladder summary showing MMR per race.

    Returns:
        Dict with showCaseEntries (up to 3 races with MMR) and allLadderMemberships
    """
    host = REGION_HOSTS.get(region_id, "eu.api.blizzard.com")
    url = f"https://{host}/sc2/profile/{region_id}/{realm_id}/{profile_id}/ladder/summary"
    return _api_get(url)


def get_match_history(region_id: int, realm_id: int, profile_id: int) -> Optional[list]:
    """Get last 25 matches from legacy API.

    Returns:
        List of match dicts with map, type, decision, date
    """
    host = REGION_HOSTS.get(region_id, "eu.api.blizzard.com")
    url = f"https://{host}/sc2/legacy/profile/{region_id}/{realm_id}/{profile_id}/matches"
    result = _api_get(url)
    if result:
        return result.get("matches", [])
    return None


def get_current_mmr(region_id: int, realm_id: int, profile_id: int) -> dict:
    """Get current MMR for each race from ladder summary.

    Returns:
        Dict mapping race name -> {mmr, wins, losses, league}
        e.g. {"Terran": {"mmr": 3720, "wins": 142, "losses": 118, "league": "diamond"}}
    """
    summary = get_ladder_summary(region_id, realm_id, profile_id)
    if not summary:
        return {}

    result = {}
    for entry in summary.get("showCaseEntries", []):
        team = entry.get("team", {})
        race = entry.get("favoriteRace", "")
        if race and team.get("mmr"):
            # Capitalize race name to match our DB format
            race_name = race.capitalize()
            result[race_name] = {
                "mmr": team["mmr"],
                "wins": team.get("wins", 0),
                "losses": team.get("losses", 0),
                "league": entry.get("league", ""),
            }

    return result


def get_profile_from_replays() -> Optional[dict]:
    """Auto-detect profile ID from parsed replay data in the DB.

    Looks at the most recent replay's toon_handle to extract region/realm/profileId.

    Returns:
        Dict with region_id, realm_id, profile_id or None
    """
    from . import db

    # Get a recent replay - we stored toon_handle-derived fields in region
    # But we also have toon_id from the replays.
    # Actually, we need to parse a replay to get toon_handle.
    # Let's check if we can extract from config or DB.

    # The replay folder path contains the profile info:
    # .../Accounts/{accountId}/{regionId}-S2-{realmId}-{profileId}/Replays/
    from .config import get_replay_folder
    import re

    folder = get_replay_folder()
    # Match pattern like: 2-S2-1-1509213
    match = re.search(r'(\d+)-S2-(\d+)-(\d+)', folder)
    if match:
        return {
            "region_id": int(match.group(1)),
            "realm_id": int(match.group(2)),
            "profile_id": int(match.group(3)),
        }

    return None


def fetch_ranked_mmr() -> dict:
    """High-level function: get current ranked MMR per race.

    Auto-detects profile from replay folder path.

    Returns:
        Dict mapping race -> {mmr, wins, losses, league} or empty dict if not configured
    """
    if not is_configured():
        return {}

    profile = get_profile_from_replays()
    if not profile:
        return {}

    return get_current_mmr(
        profile["region_id"],
        profile["realm_id"],
        profile["profile_id"],
    )
