# /opt/docker/dev/service_finder/backend/app/workers/vehicle/vehicle_robot_2_1_rdw_enricher.py
"""
Robot 2.1: RDW Enricher (Holland rendszámok dúsítása) - INTEGRÁLT SZÓTÁR ÉS MATEK
"""

import asyncio
import httpx
import logging
import json
import re
import os
import sys
from sqlalchemy import text
from app.database import AsyncSessionLocal

# Importáljuk a márkaneveket normalizáló szótárt
try:
    # Megpróbáljuk relatív úton, ha a csomagstruktúra engedi
    from .mapping_dictionary import normalize_make
except (ImportError, ValueError):
    # Ha nem, akkor a sys.path-ból vagy fallback függvény
    def normalize_make(make: str) -> str:
        m = make.upper().strip()
        synonyms = {"MERCEDES": "MERCEDES-BENZ", "VW": "VOLKSWAGEN", "ALFA": "ALFA ROMEO"}
        return synonyms.get(m, m)

logger = logging.getLogger("Robot-2-1-RDW-Enricher")
logging.basicConfig(
    level=logging.INFO, 
    format='%(asctime)s [%(levelname)s] R2.1-RDW: %(message)s',
    stream=sys.stdout
)

RDW_API_URL = "https://opendata.rdw.nl/resource/m9d7-ebf2.json?kenteken={license_plate}"
BATCH_SIZE = 10

class RDWEnricher:
    # Szótár betöltése az osztály szintjén
    BASE_PATH = os.path.dirname(__file__)
    CONFIG_PATH = os.path.join(BASE_PATH, 'mapping_config.json')
    
    try:
        with open(CONFIG_PATH, 'r', encoding='utf-8') as f:
            mapping_config = json.load(f)['rdw']
        logger.info("✅ mapping_config.json sikeresen betöltve.")
    except Exception as e:
        logger.error(f"❌ Hiba a mapping_config.json betöltésekor: {e}")
        mapping_config = {}

    @staticmethod
    def normalize_license_plate(technical_code: str) -> str:
        if not technical_code: return ""
        return re.sub(r'[-\s\.]', '', technical_code).upper()

    @classmethod
    async def fetch_candidates(cls, db):
        query = text("""
            SELECT id, make, marketing_name, technical_code, power_kw, engine_capacity,
                   body_type, raw_api_data, attempts, fuel_type, vehicle_class
            FROM vehicle.vehicle_model_definitions
            WHERE (status = 'manual_review_needed' OR status = 'unverified')
              AND technical_code IS NOT NULL AND technical_code != ''
              AND (power_kw = 0 OR engine_capacity = 0)
              AND attempts < 3
            ORDER BY priority_score DESC NULLS LAST, id ASC
            FOR UPDATE SKIP LOCKED
            LIMIT :batch_size
        """)
        result = await db.execute(query, {"batch_size": BATCH_SIZE})
        rows = result.fetchall()
        vehicles = []
        for row in rows:
            vehicles.append({
                "id": row[0], "make": row[1], "marketing_name": row[2],
                "technical_code": row[3], "power_kw": row[4] or 0,
                "engine_capacity": row[5] or 0, "body_type": row[6],
                "raw_api_data": row[7] or {}, "attempts": row[8] or 0,
                "fuel_type": row[9] or "", "vehicle_class": row[10] or ""
            })
        return vehicles

    @classmethod
    async def query_rdw_api(cls, license_plate: str, client: httpx.AsyncClient):
        url = RDW_API_URL.format(license_plate=license_plate)
        try:
            resp = await client.get(url, timeout=10.0)
            if resp.status_code == 200:
                data = resp.json()
                if isinstance(data, list) and len(data) > 0:
                    return data[0]
            return None
        except httpx.RequestError as e:
            logger.error(f"RDW hálózati hiba {license_plate}: {e}")
            return None

    @classmethod
    def extract_fields(cls, rdw_data: dict):
        """
        Adatkinyerés és dúsítás a mapping_config és a normalize_make alapján.
        """
        updates = {}
        cfg = cls.mapping_config
        if not cfg:
            return {}
        
        # 1. Alapmezők és Márkanév normalizálása
        for r_key, db_key in cfg.get('field_map', {}).items():
            val = rdw_data.get(r_key)
            if not val: continue

            if db_key == "make":
                # Használjuk a külső szótár logikát
                updates[db_key] = normalize_make(val)
            elif db_key == "body_type":
                # Karosszéria fordítás a JSON szótárból
                trans = cfg.get('body_type_translations', {})
                updates[db_key] = trans.get(val.lower(), val.upper())
            else:
                updates[db_key] = val

        # 2. KOMBINÁLT TELJESÍTMÉNY SZÁMÍTÁS (Matek Zseni 2.0)
        p_cfg = cfg.get('power_calculation', {})
        power_kw = None

        # a) Próbáljuk a direkt kW-ot (Benzin/Dízel)
        p_val = rdw_data.get(p_cfg.get('primary_source'))
        # b) Próbáljuk az elektromos kW-ot (ha az előző nincs)
        if not p_val:
            p_val = rdw_data.get(p_cfg.get('electric_source'))

        if p_val:
            try: power_kw = int(float(p_val))
            except: pass

        # c) Ha még mindig 0, jöhet a szorzás (Tömegarány * Menetkész tömeg)
        if not power_kw or power_kw == 0:
            ratio = rdw_data.get(p_cfg.get('ratio_source'))
            mass = rdw_data.get(p_cfg.get('weight_source'))
            if ratio and mass:
                try:
                    power_kw = int(float(ratio) * float(mass))
                    logger.info(f"⚡ Kiszámolt teljesítmény: {power_kw} kW ({ratio} * {mass})")
                except: pass
        
        if power_kw:
            updates['power_kw'] = power_kw

        # Hengerűrtartalom normalizálása
        if 'engine_capacity' in updates:
            try: updates['engine_capacity'] = int(float(updates['engine_capacity']))
            except: pass

        return updates

    @classmethod
    async def process_vehicle(cls, vehicle: dict, client: httpx.AsyncClient):
        license_plate = cls.normalize_license_plate(vehicle['technical_code'])
        if not license_plate:
            return vehicle, None, "empty_license_plate"

        raw_api_data = vehicle['raw_api_data']
        if not isinstance(raw_api_data, dict): raw_api_data = {}
        
        # Cache ellenőrzés (ne kérdezzük le ugyanazt 66-szor)
        rdw_data = None
        if 'rdw' in raw_api_data and len(raw_api_data['rdw']) > 0:
            rdw_data = raw_api_data['rdw'][0]['data']
        else:
            rdw_data = await cls.query_rdw_api(license_plate, client)

        if not rdw_data:
            return vehicle, None, "no_rdw_data"

        # SZÓTÁR ALAPÚ DÚSÍTÁS
        extracted = cls.extract_fields(rdw_data)
        if not extracted:
            return vehicle, None, "no_useful_data"

        updates = {}
        # Csak akkor frissítünk, ha a DB-ben még hiányos az adat (0 vagy üres)
        for key, val in extracted.items():
            if key in ['power_kw', 'engine_capacity'] and val >= 0 and vehicle[key] == 0:
                updates[key] = val
            elif key in ['make', 'body_type', 'fuel_type'] and (not vehicle.get(key) or vehicle[key] == ""):
                updates[key] = val

        # Kapuőr Logika (Arany státusz eldöntése)
        f_kw = updates.get('power_kw', vehicle['power_kw'])
        f_ccm = updates.get('engine_capacity', vehicle['engine_capacity'])
        fuel = str(updates.get('fuel_type', vehicle['fuel_type'])).lower()
        v_class = str(vehicle['vehicle_class']).lower()

        is_electric = any(x in fuel for x in ['electr', 'elektri', 'hydrogen'])
        is_gold_ready = False
        
        if 'trailer' in v_class:
            is_gold_ready = True
        elif is_electric:
            if f_kw > 0: is_gold_ready = True
            # Elektromos autóknál a hengerűrtartalom 0
            if 'engine_capacity' not in updates and vehicle['engine_capacity'] != 0:
                updates['engine_capacity'] = 0
        else:
            if f_kw > 0 and f_ccm > 0: is_gold_ready = True

        updates['_is_gold_ready'] = is_gold_ready
        updates['_new_attempts'] = vehicle['attempts'] + 1

        # Ha arany státuszba kerül, garantáljuk, hogy a power_kw és engine_capacity bekerüljön az UPDATE-be
        if is_gold_ready:
            if 'power_kw' not in updates:
                updates['power_kw'] = f_kw
            if 'engine_capacity' not in updates:
                updates['engine_capacity'] = f_ccm

        # Nyers adat mentése (ha eddig nem volt rdw kulcs)
        if 'rdw' not in raw_api_data:
            raw_api_data['rdw'] = [{'timestamp': asyncio.get_event_loop().time(), 'data': rdw_data}]
            updates['raw_api_data'] = raw_api_data

        return vehicle, updates, None

    @classmethod
    async def update_vehicle_batch(cls, db, updates_list):
        if not updates_list: return 0
        updated_count = 0
        
        for vehicle_id, updates in updates_list:
            try:
                set_clauses = []
                params = {"vehicle_id": vehicle_id}
                is_gold = updates.pop('_is_gold_ready', False)
                new_attempts = updates.pop('_new_attempts', 1)

                for key, value in updates.items():
                    if key == 'raw_api_data':
                        set_clauses.append("raw_api_data = :raw_api_data")
                        params['raw_api_data'] = json.dumps(value)
                    else:
                        set_clauses.append(f"{key} = :{key}")
                        params[key] = value

                if is_gold:
                    set_clauses.append("status = 'gold_enriched'")
                    set_clauses.append("attempts = 0")
                else:
                    set_clauses.append("attempts = :attempts")
                    params['attempts'] = new_attempts
                    if new_attempts >= 3:
                        set_clauses.append("status = 'manual_review_needed'")

                set_clauses.append("updated_at = NOW()")
                query = text(f"UPDATE vehicle.vehicle_model_definitions SET {', '.join(set_clauses)} WHERE id = :vehicle_id")
                
                # AZONNALI VÉGREHAJTÁS ÉS COMMIT!
                await db.execute(query, params)
                await db.commit()
                updated_count += 1
                
            except Exception as e:
                logger.error(f"❌ DB Mentési hiba az {vehicle_id} járműnél: {e}")
                await db.rollback() # Csak ezt a problémás autót dobjuk el
                continue
                
        return updated_count

    @classmethod
    async def run(cls):
        logger.info("🚀 Robot 2.1 (RDW) indítása...")
        
        # --- DNS ÉS KAPCSOLÓDÁSI VÉDELEM ---
        db_ready = False
        while not db_ready:
            try:
                async with AsyncSessionLocal() as db:
                    await db.execute(text("SELECT 1"))
                    db_ready = True
                    logger.info("✅ Adatbázis elérhető, indul a munka!")
            except Exception as e:
                logger.warning(f"⏳ Várakozás az adatbázisra (DNS/Hálózat hiba): {e}")
                await asyncio.sleep(5)

        while True:
            try:
                async with AsyncSessionLocal() as db:
                    vehicles = await cls.fetch_candidates(db)
                    if not vehicles:
                        await asyncio.sleep(10)
                        continue

                    async with httpx.AsyncClient(timeout=15.0) as client:
                        tasks = [cls.process_vehicle(v, client) for v in vehicles]
                        results = await asyncio.gather(*tasks)

                    updates_list = []
                    for vehicle, updates, error in results:
                        if updates:
                            updates_list.append((vehicle['id'], updates))
                            if updates.get('_is_gold_ready'):
                                logger.info(f"✨ ARANY: {vehicle['make']} {vehicle['marketing_name']}")
                        else:
                            await db.execute(
                                text("UPDATE vehicle.vehicle_model_definitions SET attempts = attempts + 1, updated_at = NOW() WHERE id = :id"), 
                                {"id": vehicle['id']}
                            )

                    if updates_list: 
                        await cls.update_vehicle_batch(db, updates_list)
                    
                    await asyncio.sleep(2)
            except Exception as e:
                logger.error(f"⚠️ Hiba a főciklusban: {e}")
                await asyncio.sleep(5)

if __name__ == "__main__":
    asyncio.run(RDWEnricher.run())