"""
parser.py — Parse les location_text Metal Archives en steps structurés.

Cas gérés :
  "Oslo"                                     → 1 step
  "Bergen (early); Oslo (later)"             → 2 steps
  "Bergen / Oslo (early)"                    → 2 rows, même step_order
  "Ski, Nordre Follo, Akershus (early)"      → 1 step, location_raw = texte complet
  "N/A", "Unknown", "", "Various"            → liste vide
  "FR", "France"                             → 1 step, is_country_only=True
"""

import re

SKIP_VALUES = frozenset({
    '', 'n/a', 'na', 'unknown', 'various', 'international',
    'various locations', 'worldwide', '-', '—', 'tba', 'tbd',
    'none', 'not available', 'disbanded', 'see comment', 'see above',
    'multiple', 'many', 'different', 'different locations',
})

STANDALONE_COUNTRY_NAMES = frozenset({
    'france', 'germany', 'italy', 'spain', 'sweden', 'norway', 'finland',
    'poland', 'netherlands', 'belgium', 'switzerland', 'austria', 'portugal',
    'greece', 'czech republic', 'slovakia', 'slovenia', 'hungary', 'ukraine',
    'russia', 'denmark', 'united kingdom', 'england', 'scotland', 'ireland',
    'northern ireland', 'wales', 'romania', 'bulgaria', 'serbia', 'croatia',
    'bosnia', 'bosnia and herzegovina', 'albania', 'estonia', 'latvia',
    'lithuania', 'iceland', 'luxembourg', 'malta', 'moldova', 'belarus',
    'georgia', 'cyprus', 'turkey', 'north macedonia', 'macedonia',
    'montenegro', 'kosovo', 'san marino', 'liechtenstein', 'monaco',
    'andorra', 'vatican',
})

# ISO2 → (lat, lon) des capitales / centroïdes de référence
COUNTRY_CENTROIDS = {
    'AD': (42.5063,  1.5218), 'AL': (41.3317, 19.8172),
    'AT': (48.2092, 16.3728), 'BA': (43.8519, 18.3866),
    'BE': (50.8503,  4.3517), 'BG': (42.6977, 23.3219),
    'BY': (53.9045, 27.5615), 'CH': (46.9480,  7.4474),
    'CY': (35.1856, 33.3823), 'CZ': (50.0880, 14.4208),
    'DE': (52.5200, 13.4050), 'DK': (55.6761, 12.5683),
    'EE': (59.4370, 24.7536), 'ES': (40.4168, -3.7038),
    'FI': (60.1699, 24.9384), 'FR': (48.8566,  2.3522),
    'GB': (51.5074, -0.1278), 'GE': (41.6941, 44.8337),
    'GR': (37.9838, 23.7275), 'HR': (45.8150, 15.9819),
    'HU': (47.4979, 19.0402), 'IE': (53.3498, -6.2603),
    'IS': (64.1355,-21.8954), 'IT': (41.9028, 12.4964),
    'LI': (47.1416,  9.5215), 'LT': (54.6872, 25.2797),
    'LU': (49.6116,  6.1319), 'LV': (56.9496, 24.1052),
    'MC': (43.7333,  7.4000), 'MD': (47.0105, 28.8638),
    'ME': (42.4304, 19.2594), 'MK': (42.0040, 21.4361),
    'MT': (35.8997, 14.5147), 'NL': (52.3676,  4.9041),
    'NO': (59.9139, 10.7522), 'PL': (52.2297, 21.0122),
    'PT': (38.7167, -9.1333), 'RO': (44.4268, 26.1025),
    'RS': (44.8176, 20.4633), 'RU': (55.7558, 37.6173),
    'SE': (59.3293, 18.0686), 'SI': (46.0511, 14.5051),
    'SK': (48.1486, 17.1077), 'SM': (43.9424, 12.4578),
    'TR': (39.9334, 32.8597), 'UA': (50.4501, 30.5234),
    'VA': (41.9029, 12.4534), 'XK': (42.6026, 20.9030),
}

COUNTRY_NAME_TO_ISO2 = {
    'france': 'FR', 'germany': 'DE', 'italy': 'IT', 'spain': 'ES',
    'sweden': 'SE', 'norway': 'NO', 'finland': 'FI', 'poland': 'PL',
    'netherlands': 'NL', 'belgium': 'BE', 'switzerland': 'CH',
    'austria': 'AT', 'portugal': 'PT', 'greece': 'GR',
    'czech republic': 'CZ', 'slovakia': 'SK', 'slovenia': 'SI',
    'hungary': 'HU', 'ukraine': 'UA', 'russia': 'RU', 'denmark': 'DK',
    'united kingdom': 'GB', 'england': 'GB', 'scotland': 'GB',
    'northern ireland': 'GB', 'wales': 'GB', 'ireland': 'IE',
    'romania': 'RO', 'bulgaria': 'BG', 'serbia': 'RS', 'croatia': 'HR',
    'bosnia': 'BA', 'bosnia and herzegovina': 'BA', 'albania': 'AL',
    'estonia': 'EE', 'latvia': 'LV', 'lithuania': 'LT', 'iceland': 'IS',
    'luxembourg': 'LU', 'malta': 'MT', 'moldova': 'MD', 'belarus': 'BY',
    'georgia': 'GE', 'cyprus': 'CY', 'turkey': 'TR',
    'north macedonia': 'MK', 'macedonia': 'MK', 'montenegro': 'ME',
    'kosovo': 'XK', 'san marino': 'SM', 'liechtenstein': 'LI',
    'monaco': 'MC', 'andorra': 'AD', 'vatican': 'VA',
}

COUNTRY_NAMES = {v: k.title() for k, v in COUNTRY_NAME_TO_ISO2.items() if len(v) == 2}
# Fix doublons (en → GB wins "United Kingdom")
COUNTRY_NAMES.update({
    'GB': 'United Kingdom', 'CZ': 'Czech Republic', 'BA': 'Bosnia and Herzegovina',
    'MK': 'North Macedonia', 'XK': 'Kosovo',
})

_ISO2_RE     = re.compile(r'^[A-Z]{2}$')
# Séparateurs de villes multiples DANS un même step. On garde uniquement "/" et
# "\" (séparateurs canoniques Metal Archives). On N'utilise PAS " and " / "&" :
# ils cassent les noms composés ("Tyne and Wear", "Bosnia and Herzegovina",
# "Newcastle upon Tyne"). Fiabilité > exhaustivité.
_CITY_SPLIT  = re.compile(r'\s*/\s*|\s*\\\s*')
_STEP_RE     = re.compile(r'([^;(]+?)(?:\s*\(([^)]+?)\))?\s*(?:;|$)')


def _classify(text: str) -> str:
    t = text.strip().lower().rstrip(';').strip()
    if t in SKIP_VALUES:
        return 'skip'
    if _ISO2_RE.match(text.strip()):
        return 'country_code'
    if t in STANDALONE_COUNTRY_NAMES:
        return 'country_name'
    return 'parseable'


def parse_location_text(location_text: str, band_country: str | None = None) -> list[dict]:
    """
    Retourne une liste de dicts, un par ligne band_locations :
      step_order     int
      step_label     str | None
      location_raw   str
      is_country_only bool
    """
    if not location_text:
        return []

    kind = _classify(location_text)
    if kind == 'skip':
        return []
    if kind == 'country_code':
        return [{'step_order': 0, 'step_label': None,
                 'location_raw': location_text.strip().upper(), 'is_country_only': True}]
    if kind == 'country_name':
        return [{'step_order': 0, 'step_label': None,
                 'location_raw': location_text.strip(), 'is_country_only': True}]

    rows = []
    step_order = 0

    for m in _STEP_RE.finditer(location_text.strip()):
        raw   = m.group(1).strip().rstrip(';').strip()
        label = (m.group(2) or '').strip() or None

        if not raw or _classify(raw) == 'skip':
            step_order += 1
            continue

        cities    = [c.strip() for c in _CITY_SPLIT.split(raw) if c.strip()]
        any_added = False

        for city in cities:
            ck = _classify(city)
            if ck == 'skip':
                continue
            rows.append({
                'step_order':    step_order,
                'step_label':    label,
                'location_raw':  city,
                'is_country_only': ck in ('country_code', 'country_name'),
            })
            any_added = True

        if any_added:
            step_order += 1

    return rows


def country_centroid(iso2: str) -> tuple[float, float] | None:
    code = iso2.strip().upper()
    if code in COUNTRY_CENTROIDS:
        return COUNTRY_CENTROIDS[code]
    name_iso = COUNTRY_NAME_TO_ISO2.get(iso2.strip().lower())
    if name_iso:
        return COUNTRY_CENTROIDS.get(name_iso)
    return None


def build_fallback_queries(location_raw: str, country_code: str | None) -> list[str]:
    """
    Construit une liste ordonnée de requêtes Geoapify (plus spécifique → plus vague).
    Le pays est injecté comme contexte à chaque niveau.
    """
    country_name = COUNTRY_NAMES.get((country_code or '').upper(), '')
    parts = [p.strip() for p in location_raw.split(',')]

    seen: set[str]   = set()
    result: list[str] = []

    def add(q: str):
        q = q.strip()
        if q and q not in seen:
            seen.add(q)
            result.append(q)

    has_country = bool(country_name) and (
        country_name.lower() in location_raw.lower()
        or (country_code and country_code.upper() in location_raw.upper())
    )

    # Requête complète + pays (si pays pas déjà dans le texte)
    if not has_country and country_name:
        add(f"{location_raw}, {country_name}")
    add(location_raw)

    # Retire les divisions administratives une par une
    for n in range(len(parts) - 1, 0, -1):
        prefix = ', '.join(parts[:n])
        if not has_country and country_name:
            add(f"{prefix}, {country_name}")
        add(prefix)

    # Juste la ville + pays
    if parts:
        city = parts[0]
        if country_name:
            add(f"{city}, {country_name}")
        add(city)

    return result
