#!/usr/bin/env python3
"""
Robot-1-Catalog-Hunter (Precíz Adattrezor + Szótár-vezérelt ETL)
Felelősség: RDW API-k lekérdezése (SZŰRTEN: Csak Autó, Motor, Teherautó), 
mapping_config.json alapú adatkinyerés, teljesítmény kalkuláció és teljes értékű mentés.
"""

import asyncio
import httpx
import logging
import os
import re
import sys
import json
from datetime import datetime
from sqlalchemy import text
from sqlalchemy.dialects.postgresql import insert
from app.database import AsyncSessionLocal
from app.models import VehicleModelDefinition

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

class CatalogHunter:
    RDW_MAIN = "https://opendata.rdw.nl/resource/m9d7-ebf2.json"
    RDW_FUEL = "https://opendata.rdw.nl/resource/8ys7-d773.json"
    RDW_ENGINE = "https://opendata.rdw.nl/resource/jh96-v4pq.json"
    RDW_TOKEN = os.getenv("RDW_APP_TOKEN")
    HEADERS = {"X-App-Token": RDW_TOKEN} if RDW_TOKEN else {}
    BATCH_SIZE = 50

    # Szótár betöltése induláskor
    CONFIG_PATH = os.path.join(os.path.dirname(__file__), "mapping_config.json")
    with open(CONFIG_PATH, 'r', encoding='utf-8') as f:
        MAPPING = json.load(f)["rdw"]

    @classmethod
    def normalize(cls, text_val: str) -> str:
        return re.sub(r'[^a-zA-Z0-9]', '', text_val).lower() if text_val else "UNKNOWN"

    @classmethod
    def parse_int(cls, value) -> int:
        try:
            return int(float(value)) if value and str(value).strip() else 0
        except:
            return 0

    @classmethod
    def parse_float(cls, value) -> float:
        try:
            return float(value) if value and str(value).strip() else 0.0
        except:
            return 0.0

    @classmethod
    async def fetch_raw_api_data(cls, client, plate: str) -> dict:
        raw_data = {"rdw_main": [], "rdw_fuel": [], "rdw_engine": []}
        try:
            # 1. RDW Main
            main_resp = await client.get(f"{cls.RDW_MAIN}?kenteken={plate}", headers=cls.HEADERS)
            if main_resp.status_code == 200: raw_data["rdw_main"] = main_resp.json()

            # 2. RDW Fuel
            fuel_resp = await client.get(f"{cls.RDW_FUEL}?kenteken={plate}", headers=cls.HEADERS)
            if fuel_resp.status_code == 200: raw_data["rdw_fuel"] = fuel_resp.json()

            # 3. RDW Engine
            engine_resp = await client.get(f"{cls.RDW_ENGINE}?kenteken={plate}", headers=cls.HEADERS)
            if engine_resp.status_code == 200: raw_data["rdw_engine"] = engine_resp.json()

        except Exception as e:
            logger.error(f"Hiba a nyers adatok lekérése közben ({plate}): {e}")
        return raw_data

    @classmethod
    def apply_mapping(cls, raw_main: dict, raw_fuel: list, raw_engine: list) -> dict:
        """ A JSON szótár alapján kinyeri és kiszámolja a pontos értékeket. """
        tech = {
            "make": raw_main.get("merk", "UNKNOWN").strip().upper(),
            "marketing_name": raw_main.get("handelsbenaming", "UNKNOWN").upper(),
            "curb_weight": cls.parse_int(raw_main.get("massa_ledig_voertuig")),
            "max_weight": cls.parse_int(raw_main.get("technische_max_massa_voertuig")),
            "engine_capacity": cls.parse_int(raw_main.get("cilinderinhoud")),
            "cylinders": cls.parse_int(raw_main.get("aantal_cilinders")),
            "wheelbase": cls.parse_int(raw_main.get("wielbasis")),
            "doors": cls.parse_int(raw_main.get("aantal_deuren")),
            "seats": cls.parse_int(raw_main.get("aantal_zitplaatsen")),
            "list_price": cls.parse_int(raw_main.get("catalogusprijs")),
            "max_speed": cls.parse_int(raw_main.get("maximale_constructiesnelheid")),
            "year_from": 0,
            "power_kw": 0,
            "engine_code": None,
            "euro_class": None,
            "fuel_type": "Unknown",
            "co2": 0,
            "consumption": 0.0,
            "body_type": "UNKNOWN"
        }

        # Évjárat kivágása (pl. "20240424" -> 2024)
        datum = str(raw_main.get("datum_eerste_toelating", ""))
        if len(datum) >= 4:
            tech["year_from"] = cls.parse_int(datum[:4])

        # Karosszéria fordítás
        raw_body = str(raw_main.get("inrichting", "")).lower().strip()
        tech["body_type"] = cls.MAPPING["body_type_translations"].get(raw_body, raw_body.upper())

        # Üzemanyag adatok kinyerése
        if raw_fuel:
            f = raw_fuel[0]
            raw_fuel_type = f.get("brandstof_omschrijving", "Unknown")
            tech["fuel_type"] = cls.MAPPING["fuel_translations"].get(raw_fuel_type, raw_fuel_type)
            tech["euro_class"] = f.get("euro_klasse") or f.get("uitlaatemissieniveau")
            tech["co2"] = cls.parse_int(f.get("co2_uitstoot_gecombineerd"))
            tech["consumption"] = cls.parse_float(f.get("brandstofverbruik_gecombineerd"))

            # --- JAVÍTOTT TELJESÍTMÉNY-KERESŐ (Normál, Elektromos, Névleges) ---
            p_normal = cls.parse_float(f.get("nettomaximumvermogen"))
            p_elec = cls.parse_float(f.get("netto_max_vermogen_elektrisch"))
            p_nominal = cls.parse_float(f.get("nominaal_continu_maximumvermogen"))
            
            power = max(p_normal, p_elec, p_nominal)
            
            # HA MÉG MINDIG NINCS TELJESÍTMÉNY, SZÁMOLJUK KI A SÚLY/ARÁNYBÓL!
            if power == 0:
                ratio_key = cls.MAPPING["power_calculation"]["ratio_source"]
                weight_key = cls.MAPPING["power_calculation"]["weight_source"]
                ratio = cls.parse_float(raw_main.get(ratio_key))
                weight = cls.parse_float(raw_main.get(weight_key))
                if ratio > 0 and weight > 0:
                    power = ratio * weight
                    logger.info(f"⚡ Teljesítmény számolva arányból: {ratio} * {weight} = {power:.2f} kW")
            
            tech["power_kw"] = cls.parse_int(power)

        # Motor adatok kinyerése
        if raw_engine:
            tech["engine_code"] = raw_engine[0].get("motorcode")

        return tech

    @classmethod
    async def process_task(cls, db, task):
        clean_make = task.make.strip().upper()
        clean_model = task.model.strip().upper()
        logger.info(f"🎯 PRECÍZIÓS ADATGYŰJTÉS INDUL: {clean_make} {clean_model}")

        async with httpx.AsyncClient(timeout=30.0) as client:
            offset = 0
            while True:
                # --- SZŰRÉS: Csak autó, motor és teherautó/kamion ---
                allowed_types = "('Personenauto','Motorfiets','Vrachtwagen')"
                params = f"merk={clean_make}&$where=voertuigsoort IN {allowed_types}"
                
                if clean_model != 'ALL_VARIANTS':
                    params += f" AND handelsbenaming='{clean_model}'"
                    
                params += f"&$limit={cls.BATCH_SIZE}&$offset={offset}&$order=kenteken DESC"

                try:
                    r = await client.get(f"{cls.RDW_MAIN}?{params}", headers=cls.HEADERS)
                    batch = r.json() if r.status_code == 200 else []
                except Exception as e:
                    logger.error(f"Hiba a batch lekérés közben: {e}")
                    break

                if not batch: break

                for item in batch:
                    plate = item.get("kenteken", "UNKNOWN")
                    try:
                        async with db.begin_nested():
                            raw_api_data = await cls.fetch_raw_api_data(client, plate)
                            
                            # Szótár és Matek alkalmazása!
                            tech = cls.apply_mapping(
                                raw_api_data.get("rdw_main", [{}])[0] if raw_api_data.get("rdw_main") else item,
                                raw_api_data.get("rdw_fuel", []),
                                raw_api_data.get("rdw_engine", [])
                            )

                            norm_name = cls.normalize(tech["marketing_name"].replace(clean_make, "").strip() or tech["marketing_name"])

                            # Routing Logika
                            has_power_and_ccm = tech["power_kw"] > 0 and tech["engine_capacity"] > 0
                            is_electric = "electric" in tech["fuel_type"].lower()
                            
                            if has_power_and_ccm or (tech["power_kw"] > 0 and is_electric):
                                final_status = "awaiting_ai_synthesis"
                            else:
                                final_status = "unverified"

                            stmt = insert(VehicleModelDefinition).values(
                                market='EU',
                                make=tech["make"],
                                marketing_name=tech["marketing_name"],
                                normalized_name=norm_name,
                                variant_code=item.get("variant", "UNKNOWN"),
                                version_code=item.get("uitvoering", "UNKNOWN"),
                                technical_code=plate,
                                type_approval_number=item.get("typegoedkeuringsnummer"),
                                seats=tech["seats"],
                                doors=tech["doors"],
                                width=cls.parse_int(item.get("breedte")),
                                wheelbase=tech["wheelbase"],
                                list_price=tech["list_price"],
                                max_speed=tech["max_speed"],
                                curb_weight=tech["curb_weight"],
                                max_weight=tech["max_weight"],
                                fuel_consumption_combined=tech["consumption"],
                                co2_emissions_combined=tech["co2"],
                                vehicle_class=task.vehicle_class,
                                body_type=tech["body_type"],
                                fuel_type=tech["fuel_type"],
                                engine_capacity=tech["engine_capacity"],
                                power_kw=tech["power_kw"],
                                cylinders=tech["cylinders"],
                                engine_code=tech["engine_code"],
                                euro_classification=tech["euro_class"],
                                year_from=tech["year_from"],
                                priority_score=task.priority_score,
                                status=final_status,
                                source="ROBOT-1-PRECISION-MAPPER",
                                raw_search_context='',
                                raw_api_data=raw_api_data,
                                research_metadata={},
                                specifications={"fast_track": True} if final_status == "awaiting_ai_synthesis" else {},
                                marketing_name_aliases=[]
                            ).on_conflict_do_update(
                                index_elements=['make', 'normalized_name', 'variant_code', 'version_code', 'fuel_type', 'market', 'year_from'],
                                set_={
                                    'power_kw': tech["power_kw"],
                                    'engine_capacity': tech["engine_capacity"],
                                    'fuel_type': tech["fuel_type"],
                                    'body_type': tech["body_type"],
                                    'doors': tech["doors"],
                                    'seats': tech["seats"],
                                    'status': final_status,
                                    'raw_api_data': raw_api_data,
                                    'updated_at': datetime.utcnow()
                                }
                            ).returning(VehicleModelDefinition.id)

                            res = await db.execute(stmt)
                            vmd_id = res.scalar()

                            if final_status == "awaiting_ai_synthesis" and vmd_id:
                                cat_stmt = text("""
                                    INSERT INTO vehicle.vehicle_catalog (master_definition_id, make, model, power_kw, engine_capacity, fuel_type, factory_data)
                                    VALUES (:m_id, :make, :model, :kw, :ccm, :fuel, :factory)
                                    ON CONFLICT ON CONSTRAINT uix_vehicle_catalog_full DO NOTHING;
                                """)
                                await db.execute(cat_stmt, {
                                    "m_id": vmd_id,
                                    "make": tech["make"],
                                    "model": tech["marketing_name"][:50],
                                    "kw": tech["power_kw"],
                                    "ccm": tech["engine_capacity"],
                                    "fuel": tech["fuel_type"],
                                    "factory": '{"source": "RDW Mapping System"}'
                                })

                    except Exception as e:
                        logger.warning(f"⚠️ Sor hiba ({plate}): {e}")

                await db.commit()
                offset += len(batch)
                if offset >= 500: break
                await asyncio.sleep(0.5)

            await db.execute(
                text("UPDATE vehicle.catalog_discovery SET status = 'processed' WHERE id = :id"),
                {"id": task.id}
            )
            await db.commit()

    @classmethod
    async def run(cls):
        logger.info("🤖 Robot-1-Nyers ONLINE (Precíz Szótár-alapú feldolgozás + Jármű szűrés)")
        while True:
            try:
                async with AsyncSessionLocal() as db:
                    res = await db.execute(text("""
                        UPDATE vehicle.catalog_discovery 
                        SET status = 'processing' 
                        WHERE id = (
                            SELECT id FROM vehicle.catalog_discovery 
                            WHERE status = 'pending' 
                            ORDER BY priority_score DESC 
                            FOR UPDATE SKIP LOCKED LIMIT 1
                        ) RETURNING id, make, model, vehicle_class, priority_score;
                    """))
                    task = res.fetchone()
                    await db.commit()

                if task:
                    await cls.process_task(db, task)
                else:
                    await asyncio.sleep(30)
            except Exception as e:
                logger.error(f"Hiba a fő ciklusban: {e}")
                await asyncio.sleep(10)

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