"""Symbol normalisation and categorization utilities."""

from __future__ import annotations

from typing import Optional

# Well-known symbols by category (mirrors the server-side table)
_FOREX = {
    "EURUSD", "GBPUSD", "USDJPY", "USDCHF", "AUDUSD", "USDCAD",
    "NZDUSD", "EURGBP", "EURJPY", "GBPJPY", "AUDJPY", "EURAUD",
    "EURCHF", "GBPCHF", "CHFJPY", "CADJPY", "AUDNZD", "AUDCAD",
    "AUDCHF", "EURNZD", "EURCAD", "CADCHF", "NZDJPY", "GBPAUD",
    "GBPCAD", "GBPNZD", "NZDCAD", "NZDCHF", "USDSGD", "USDHKD",
    "USDCNH",
}
_METAL = {"XAUUSD", "XAGUSD"}
_COMMODITY = {"UKOUSD", "USOUSD"}
_INDEX = {"U30USD", "NASUSD", "SPXUSD", "100GBP", "D30EUR", "E50EUR", "H33HKD"}
_CRYPTO = {
    "BTCUSD", "ETHUSD", "LTCUSD", "BCHUSD", "XMRUSD", "BNBUSD",
    "SOLUSD", "ADAUSD", "DOGUSD", "XSIUSD", "AVEUSD", "DSHUSD",
    "RPLUSD", "LNKUSD",
}
_STOCK = {
    "AAPL", "AMZN", "BABA", "GOOGL", "META", "MSFT", "NFLX", "NVDA",
    "TSLA", "ABBV", "ABNB", "ABT", "ADBE", "AMD", "AVGO", "C",
    "CRM", "DIS", "GS", "INTC", "JNJ", "MA", "MCD", "KO", "MMM",
    "NIO", "PLTR", "SHOP", "TSM", "V",
}
_ALL_KNOWN = _FOREX | _METAL | _COMMODITY | _INDEX | _CRYPTO | _STOCK


def normalize_symbol(raw: str) -> str:
    """Normalize a raw broker symbol to the standard form.

    Strips common suffixes added by brokers (e.g. ".", "_" suffixes).

    Parameters
    ----------
    raw : str
        e.g. "XAUUSD.a", "EURUSDm", "NASUSDc"

    Returns
    -------
    str
        Normalized symbol in uppercase, e.g. "XAUUSD", "EURUSD".
    """
    if not raw:
        return ""
    s = raw.strip().upper()
    if s in _ALL_KNOWN:
        return s
    # Try trimming 1-4 trailing chars
    for trim in range(1, 5):
        candidate = s[:-trim] if len(s) > trim else ""
        if candidate in _ALL_KNOWN:
            return candidate
    # Try stripping after '.' or '_'
    if "." in s:
        candidate = s.split(".")[0]
        if candidate in _ALL_KNOWN:
            return candidate
    if "_" in s:
        candidate = s.split("_")[0]
        if candidate in _ALL_KNOWN:
            return candidate
    return s


def guess_category(symbol: str) -> str:
    """Guess the product category for a symbol.

    Returns one of: forex, metal, commodity, index, crypto, stock, unknown.
    """
    s = normalize_symbol(symbol)
    if s in _FOREX:
        return "forex"
    if s in _METAL:
        return "metal"
    if s in _COMMODITY:
        return "commodity"
    if s in _INDEX:
        return "index"
    if s in _CRYPTO:
        return "crypto"
    if s in _STOCK:
        return "stock"
    return "unknown"


def get_known_symbols() -> set[str]:
    """Return the set of all known symbol names."""
    return set(_ALL_KNOWN)
