import asyncio
import httpx
import logging
import os
import re
import sys
from sqlalchemy import text, select
from sqlalchemy.dialects.postgresql import insert
from app.database import AsyncSessionLocal
from app.models.vehicle_definitions import VehicleModelDefinition

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

class CatalogHunter:
    """
    Vehicle Robot 1.9.2: The Invincible Mega-Hunter (CONCURRENCY PATCH)
    Szigorú sor-zárolás (SKIP LOCKED) és exponenciális API újrapróbálkozás.
    """
    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

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

    @classmethod
    def parse_int(cls, value) -> int:
        try:
            if value is None or str(value).strip() == "": return 0
            return int(float(value))
        except (ValueError, TypeError): return 0

    @classmethod
    def parse_float(cls, value) -> float:
        try:
            if value is None or str(value).strip() == "": return 0.0
            return float(value)
        except (ValueError, TypeError): return 0.0

    @classmethod
    async def fetch_with_retry(cls, client: httpx.AsyncClient, url: str, retries: int = 3):
        """ Hibatűrő HTTP kérés API leállások és Rate Limitek ellen. """
        for attempt in range(retries):
            try:
                resp = await client.get(url, headers=cls.HEADERS)
                if resp.status_code == 200:
                    return resp
                elif resp.status_code == 429: # Rate limit
                    await asyncio.sleep(2 ** attempt) # 1, 2, 4 másodperc pihenő
                else:
                    return resp # Egyéb hiba (pl 404), nem próbáljuk újra
            except httpx.RequestError as e:
                if attempt == retries - 1:
                    logger.debug(f"API Hiba végleges ({url}): {e}")
                    raise
                await asyncio.sleep(2 ** attempt)
        return None

    @classmethod
    async def fetch_tech_details(cls, client, plate):
        results = {
            "power_kw": 0, "engine_code": None, "euro_class": None, 
            "fuel_desc": "Unknown", "co2": 0, "consumption": 0.0
        }
        try:
            f_resp = await cls.fetch_with_retry(client, f"{cls.RDW_FUEL}?kenteken={plate}")
            if f_resp and f_resp.status_code == 200 and f_resp.json():
                f = f_resp.json()[0]
                p1 = cls.parse_int(f.get("netto_maximum_vermogen") or f.get("nettomaximumvermogen"))
                p2 = cls.parse_int(f.get("nominaal_continu_maximum_vermogen") or f.get("nominaalcontinuvermogen"))
                results.update({
                    "power_kw": max(p1, p2),
                    "fuel_desc": f.get("brandstof_omschrijving") or "Unknown",
                    "euro_class": f.get("euro_klasse") or f.get("uitlaatemissieniveau"),
                    "co2": cls.parse_int(f.get("co2_uitstoot_gecombineerd")),
                    "consumption": cls.parse_float(f.get("brandstofverbruik_gecombineerd"))
                })
            
            e_resp = await cls.fetch_with_retry(client, f"{cls.RDW_ENGINE}?kenteken={plate}")
            if e_resp and e_resp.status_code == 200 and e_resp.json():
                results["engine_code"] = e_resp.json()[0].get("motorcode")
        except Exception as e:
            logger.debug(f"Hiba a technikai részleteknél ({plate}): {e}")
        return results

    @classmethod
    async def process_make_model(cls, db, task_id, make_name, model_name, v_class, priority):
        clean_make = make_name.strip().upper()
        clean_model = model_name.strip().upper()
        logger.info(f"🎯 IPARI ADATBÁNYÁSZAT INDUL: {clean_make} {clean_model}")
        
        offset = 0
        async with httpx.AsyncClient(timeout=30.0) as client:
            while True:
                params = f"merk={clean_make}&handelsbenaming={clean_model}&$limit={cls.BATCH_SIZE}&$offset={offset}&$order=kenteken DESC"
                try:
                    r = await cls.fetch_with_retry(client, f"{cls.RDW_MAIN}?{params}")
                    batch = r.json() if r and r.status_code == 200 else []
                except Exception: break
                
                if not batch: break 

                for item in batch:
                    try:
                        plate = item.get("kenteken")
                        if not plate: continue
                        
                        variant = item.get("variant") or "UNKNOWN"
                        version = item.get("uitvoering") or "UNKNOWN"
                        ccm = cls.parse_int(item.get("cilinderinhoud"))
                        
                        norm_name = cls.normalize(clean_model.replace(clean_make, "").strip() or clean_model)
                        
                        tech = await cls.fetch_tech_details(client, plate)

                        stmt = insert(VehicleModelDefinition).values(
                            make=clean_make,
                            marketing_name=clean_model,
                            normalized_name=norm_name,
                            variant_code=variant,
                            version_code=version,
                            type_approval_number=item.get("typegoedkeuringsnummer"),
                            technical_code=plate,
                            engine_capacity=ccm,
                            power_kw=tech["power_kw"],
                            fuel_type=tech["fuel_desc"],
                            engine_code=tech["engine_code"],
                            seats=cls.parse_int(item.get("aantal_zitplaatsen")),
                            doors=cls.parse_int(item.get("aantal_deuren")),
                            width=cls.parse_int(item.get("breedte")),
                            wheelbase=cls.parse_int(item.get("wielbasis")),
                            list_price=cls.parse_int(item.get("catalogusprijs")),
                            max_speed=cls.parse_int(item.get("maximale_constructiesnelheid")),
                            towing_weight_unbraked=cls.parse_int(item.get("maximum_massa_trekken_ongeremd")),
                            towing_weight_braked=cls.parse_int(item.get("maximum_trekken_massa_geremd")),
                            curb_weight=cls.parse_int(item.get("massa_ledig_voertuig")),
                            max_weight=cls.parse_int(item.get("technische_max_massa_voertuig") or item.get("toegestane_maximum_massa_voertuig")),
                            body_type=item.get("inrichting"),
                            co2_emissions_combined=tech["co2"],
                            fuel_consumption_combined=tech["consumption"],
                            euro_classification=tech["euro_class"],
                            cylinders=cls.parse_int(item.get("aantal_cilinders")),
                            vehicle_class=v_class,
                            priority_score=priority,
                            status="ACTIVE",
                            source="MEGA-HUNTER-v1.9.2"
                        )
                        
                        do_nothing_stmt = stmt.on_conflict_do_nothing(
                            index_elements=['make', 'normalized_name', 'variant_code', 'version_code', 'fuel_type']
                        )
                        
                        await db.execute(do_nothing_stmt)

                    except Exception as e:
                        logger.warning(f"⚠️ Hiba a sor feldolgozásakor ({plate}): {e}")
                
                try:
                    await db.commit()
                except Exception as e:
                    await db.rollback()
                    logger.error(f"❌ Batch commit hiba (Ignorálva): {e}")

                offset += len(batch)
                if offset >= 500: break 
                await asyncio.sleep(0.5) # Lassítjuk kicsit a terhelést
            
            # Discovery státusz frissítése
            await db.execute(text("UPDATE data.catalog_discovery SET status = 'processed' WHERE id = :id"), {"id": task_id})
            await db.commit()

    @classmethod
    async def run(cls):
        logger.info("🤖 Invincible Mega-Hunter v1.9.2 ONLINE (CONCURRENCY PATCHED)")
        while True:
            async with AsyncSessionLocal() as db:
                # ATOMI ZÁROLÁS (Race condition ellenszere)
                # Keresünk egy pending feladatot, azonnal zároljuk és átállítjuk processingre!
                query = text("""
                    UPDATE data.catalog_discovery
                    SET status = 'processing'
                    WHERE id = (
                        SELECT id FROM data.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 = (await db.execute(query)).fetchone()
                await db.commit()
                
                if task: 
                    await cls.process_make_model(db, task[0], task[1], task[2], task[3], task[4])
                else: 
                    await asyncio.sleep(30)

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