"""Traducción al inglés de los nombres de categoría de la tienda.

Es una LIBRERÍA: la usa `gen_store_catalog.py` para el `name_en` del seed.
Ejecutándolo se comprueban traducciones sueltas (nombres por stdin).

Prioridad: términos OFICIALES sacados de los DB2 del cliente (ChrClasses,
ItemSet, ItemSubClass) y de los nombres bilingües de home_item_data. Solo se
traduce a mano lo que la tienda se inventó y no existe en el juego.
"""
import json
import os
import re
import sys

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import wdc_db2

HERE = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(HERE, '..', 'store_category_en.sql')


def _pairs(table, field):
    """Pares es->en de un campo string, casando por id entre los dos locales."""
    out = {}
    for loc in ('esES', 'enUS'):
        t = wdc_db2.DB2(f'/root/{loc}/{table}.db2')
        out[loc] = {rid: t.string_at(i, field, row[field]) for i, (rid, row) in enumerate(t.rows)}
    return {out['esES'][k]: out['enUS'][k] for k in out['esES']
            if k in out['enUS'] and out['esES'][k]}


# Términos OFICIALES del juego, sacados del cliente: nunca inventados.
oficial = {}
oficial.update(_pairs('ChrClasses', 0))     # Name_lang
oficial.update(_pairs('ItemSet', 0))        # Name_lang
oficial.update(_pairs('ItemSubClass', 0))   # DisplayName_lang
oficial.update(_pairs('ItemSubClass', 1))   # VerboseName_lang
# case-insensitive: las categorías capitalizan distinto que los ItemSet
# ("Las Diez Tormentas" vs "Las diez tormentas").
OF = {k.lower(): v for k, v in oficial.items()}

# Términos extraídos de los nombres bilingües de ítem (no están en ItemSet:
# los sets de PvP de WotLK no son ItemSets reales). Verificados con
# `SELECT name_es, name_en FROM home_item_data WHERE name_es LIKE ...`.
OF.update({
    'gladiador furioso': 'Furious Gladiator',
    'gladiador incansable': 'Relentless Gladiator',
    'gladiador indómito': 'Savage Gladiator',
    'gladiador mortal': 'Deadly Gladiator',
    'gladiador odioso': 'Hateful Gladiator',
})

# Vocabulario de la tienda (no son términos del juego; traducción manual).
ROL = {
    'DPS caster': 'Caster DPS', 'DPS melee': 'Melee DPS', 'DPS Sanador': 'Healer DPS',
    'DPS': 'DPS', 'Sanador': 'Healer', 'Tanque': 'Tank',
    'Cuero': 'Leather', 'Malla': 'Mail', 'Placas': 'Plate', 'Tela': 'Cloth',
    'Indómito': 'Savage', 'Mortal': 'Deadly', 'Odioso': 'Hateful',
}
MATERIAL = {'cuero': 'Leather', 'malla': 'Mail', 'placa': 'Plate', 'placas': 'Plate',
            'tela': 'Cloth'}
PIEZA = {'Botas': 'Boots', 'Brazales': 'Bracers', 'Cinturones': 'Belts'}
MANUAL = {
    'Abalorios': 'Trinkets', 'Anillos': 'Rings', 'Collares': 'Necks', 'Capas': 'Cloaks',
    'Hombreras': 'Shoulders', 'Pecheras': 'Chests', 'Tabardos': 'Tabards',
    'Escudos': 'Shields', 'Sostener': 'Held In Off-hand', 'Una mano': 'One-Hand',
    'Dos manos': 'Two-Hand', 'Joyería': 'Jewelry', 'Armas': 'Weapons',
    'Bolsas': 'Bags', 'Bolsa de almas': 'Soul Bag', 'Bolsas de profesiones': 'Profession Bags',
    'Contenedores': 'Containers', 'Consumibles': 'Consumables', 'Pociones': 'Potions',
    'Elíxires': 'Elixirs', 'Frascos': 'Flasks', 'Pergaminos': 'Scrolls',
    'Comidas y bebidas': 'Food & Drinks', 'Esencias y polvos': 'Essences & Powders',
    'Hierbas': 'Herbs', 'Minerales': 'Ores', 'Telas': 'Cloth', 'Cueros': 'Leather',
    'Mascotas': 'Pets', 'Elementales': 'Elementals', 'Monedas': 'Currencies',
    'Monturas terrestres': 'Ground Mounts', 'Monturas voladoras': 'Flying Mounts',
    'Piedra hogar': 'Hearthstone', 'Miscelánea': 'Miscellaneous', 'Varios': 'Miscellaneous',
    'Mejoras de objetos': 'Item Enhancements', 'Objetos de misión': 'Quest Items',
    'Objetos comerciables': 'Trade Goods', 'Misiones repetibles': 'Repeatable Quests',
    'Items de leveo': 'Leveling Items', 'Moneda de transfiguración': 'Transmog Currency',
    'Tokens de Armadura': 'Armor Tokens',
    # "Exalted" verificado con sus propios ítems: "Casco exaltado" = "Exalted Helmet".
    'Placa Exaltada': 'Exalted Plate',
    'Carcajs | Munición': 'Quivers | Ammo',
    # Los DB2 solo traen "Espadas de una mano"/"de dos manos"; la tienda las
    # agrupa, así que va el plural genérico del término oficial.
    'Espadas': 'Swords', 'Hachas': 'Axes', 'Mazas': 'Maces', 'Arrojadizas': 'Thrown',
    # "Sacedorte" era una errata de "Sacerdote" (códigos 3-10, 4-10 y 19-9). Ya
    # está corregida en la BD y en el seed store_catalog.sql; se deja mapeada por
    # si queda alguna BD antigua sin corregir.
    'Sacedorte': 'Priest',
    "Templo de Ahn'Qiraj": "Temple of Ahn'Qiraj",
    # El ItemSet oficial se llama "Equipo de batalla DE runaoscura"; la categoría
    # se come el "de", así que no casa ni ignorando mayúsculas. El inglés sale
    # igualmente del ItemSet.
    'Equipo de Batalla Runaoscura': 'Darkruned Battlegear',
    # Compuesto de dos términos oficiales: el ItemSet "Equipo de batalla de
    # Iluminado" = "Lightbringer Battlegear", y "Fuente del Sol" = "Sunwell"
    # (ítem "Hoja de La Fuente del Sol" = "Sunwell Blade"). Son las piezas T6.5
    # de paladín. NO es "Sunwell Radiance", que es un buff, no un set.
    'Equipo de Batalla del Iluminado de la Fuente del Sol': 'Sunwell Lightbringer Battlegear',
}


def tr(name):
    n = name.strip()

    # Nombres que son solo un código ("11-1", "23-10"): no son español.
    if re.fullmatch(r'[\d.\-]+', n):
        return n
    # Nombres que ya están en inglés: "Tier 7.1 (PvE)", "Tier 4 (PvE) | Tier 1 (PvP)".
    if re.fullmatch(r'Tier [\d.]+ \(Pv[EP]\)( \| Tier [\d.]+ \(Pv[EP]\))?', n):
        return n

    if n in MANUAL:
        return MANUAL[n]
    if n.lower() in OF:
        return OF[n.lower()]

    # "X (sufijo)": traducir cada parte por separado. Si el sufijo no se sabe
    # traducir se deja igual ("(T2 Recolor)" ya está en inglés); si no se sabe
    # traducir la base, se abandona la regla -> nunca se interpola None.
    m = re.fullmatch(r'(.+?) \((.+)\)', n)
    if m:
        base, suf = m.groups()
        b = tr(base)
        if b:
            return f'{b} ({ROL.get(suf) or tr(suf) or suf})'

    rules = [
        (r'^Nivel de objeto (.+)$', lambda m: f'Item Level {m.group(1)}'),
        (r'^Set de banda tier (.+)$', lambda m: f'Tier {m.group(1)} Raid Set'),
        (r'^Set de mazmorra (.+)$', lambda m: f'Dungeon Set {m.group(1)}'),
        (r'^Set inicial (.+)$', lambda m: f'Starter Set {m.group(1)}'),
        (r'^Set de Temporada de Arenas (.+)$', lambda m: f'Arena Season {m.group(1)} Set'),
        (r'^Temporada de Arenas (.+)$', lambda m: f'Arena Season {m.group(1)}'),
        (r'^Set del (.+)$', lambda m: f'{tr(m.group(1))} Set' if tr(m.group(1)) else None),
        (r'^Reliquia (PvE|PvP)$', lambda m: f'{m.group(1)} Relic'),
        (r'^Sets de armadura (PvE|PvP) \[Nivel (.+) a (.+)\]$',
         lambda m: f'{m.group(1)} Armor Sets [Level {m.group(2)} to {m.group(3)}]'),
        (r'^Sets de armadura (PvE|PvP) \[Nivel (.+)\]$',
         lambda m: f'{m.group(1)} Armor Sets [Level {m.group(2)}]'),
        (r'^Sets de transfiguración (PvE|PvP) \[Hasta nivel (.+)\]$',
         lambda m: f'{m.group(1)} Transmog Sets [Up to level {m.group(2)}]'),
        (r'^Armas de transfiguración (PvE|PvP) \[Hasta nivel (.+)\]$',
         lambda m: f'{m.group(1)} Transmog Weapons [Up to level {m.group(2)}]'),
        (r'^Accesorios de Transfiguración (PvE|PvP) \[Hasta nivel (.+)\]$',
         lambda m: f'{m.group(1)} Transmog Accessories [Up to level {m.group(2)}]'),
        (r'^Armas (PvE|PvP) \[Nivel (.+) a (.+)\]$',
         lambda m: f'{m.group(1)} Weapons [Level {m.group(2)} to {m.group(3)}]'),
        (r'^Accesorios (PvE|PvP) \[Nivel (.+) a (.+)\]$',
         lambda m: f'{m.group(1)} Accessories [Level {m.group(2)} to {m.group(3)}]'),
        # Piezas de armadura: "<Pieza> de <material>" (los datos traen "placa" y
        # "placas" indistintamente para lo mismo)
        (r'^(Botas|Brazales|Cinturones) de (cuero|malla|placa|placas|tela)$',
         lambda m: f'{MATERIAL[m.group(2)]} {PIEZA[m.group(1)]}'),
        # "(T2 Recolor)" ya está en inglés: se conserva y se traduce solo la base
        (r'^(.+) \(T(\d) Recolor\)$',
         lambda m: f'{tr(m.group(1))} (T{m.group(2)} Recolor)' if tr(m.group(1)) else None),
    ]
    for pat, fn in rules:
        m = re.fullmatch(pat, n)
        if m:
            return fn(m)
    return None  # sin traducir


if __name__ == '__main__':
    # Modo comprobación: pásale nombres por stdin y dice cómo los traduce.
    # El seed lo genera `gen_store_catalog.py`, que importa `tr` de aquí.
    names = [l.rstrip('\n') for l in sys.stdin if l.strip()]
    if not names:
        sys.exit('Uso: ... | python translate_categories.py   (comprueba traducciones)\n'
                 'Para regenerar el catálogo: python gen_store_catalog.py')
    for n in names:
        t = tr(n)
        print('%-52s -> %s' % (n, t if t else '*** SIN TRADUCIR ***'))
