# /opt/docker/dev/service_finder/backend/app/workers/vehicle/vehicle_robot_1_catalog_hunter.py
# version: 1.9.6
import asyncio
import httpx
import logging
import os
import re
import sys
from datetime import datetime
from sqlalchemy import text, func
from sqlalchemy.dialects.postgresql import insert
from app.database import AsyncSessionLocal
from app.models.vehicle_definitions import VehicleModelDefinition

# MB 2.0 Standard Naplózás
logging.basicConfig(
    level=logging.INFO, 
    format='%(asctime)s [%(levelname)s] Robot-1-Hunter: %(message)s', 
    stream=sys.stdout
)
logger = logging.getLogger("Robot-1-Hunter")

class CatalogHunter:
    """
    Vehicle Robot 1.9.6: Mega-Hunter (TIMESTAMP & INTEGRITY PATCH)
    Kezeli az ALL_VARIANTS-t, a Savepoint-okat és az összes kötelező mezőt.
    """
    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):
        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: await asyncio.sleep(2 ** attempt)
                else: return resp
            except httpx.RequestError:
                if attempt == retries - 1: 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: pass
        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"🎯 ADATGYŰJTÉS INDUL: {clean_make} {clean_model}")
        
        offset = 0
        async with httpx.AsyncClient(timeout=30.0) as client:
            while True:
                if clean_model == 'ALL_VARIANTS':
                    params = f"merk={clean_make}&$limit={cls.BATCH_SIZE}&$offset={offset}&$order=kenteken DESC"
                else:
                    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:
                    plate = item.get("kenteken", "UNKNOWN")
                    try:
                        async with db.begin_nested():
                            tech = await cls.fetch_tech_details(client, plate)
                            actual_model = (item.get("handelsbenaming") or clean_model).upper()
                            norm_name = cls.normalize(actual_model.replace(clean_make, "").strip() or actual_model)

                            stmt = insert(VehicleModelDefinition).values(
                                make=clean_make,
                                marketing_name=actual_model,
                                normalized_name=norm_name,
                                variant_code=item.get("variant", "UNKNOWN"),
                                version_code=item.get("uitvoering", "UNKNOWN"),
                                technical_code=plate,
                                engine_capacity=cls.parse_int(item.get("cilinderinhoud")),
                                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")),
                                curb_weight=cls.parse_int(item.get("massa_ledig_voertuig")),
                                max_weight=cls.parse_int(item.get("technische_max_massa_voertuig")),
                                vehicle_class=v_class,
                                priority_score=priority,
                                market='EU', # KÖTELEZŐ
                                status="unverified",
                                is_manual=False,
                                created_at=func.now(), # KÖTELEZŐ DÁTUMOK
                                updated_at=func.now(),
                                source="MEGA-HUNTER-v1.9.6"
                            ).on_conflict_do_nothing(
                                index_elements=['make', 'normalized_name', 'variant_code', 'version_code', 'fuel_type']
                            )
                            await db.execute(stmt)
                    except Exception as e:
                        logger.warning(f"⚠️ Sor eldobva ({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("🤖 Mega-Hunter v1.9.6 ONLINE (TIMESTAMP PATCH)")
        while True:
            try:
                async with AsyncSessionLocal() as db:
                    query = 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;
                    """)
                    result = await db.execute(query)
                    task = result.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)
            except Exception as e:
                logger.error(f"💀 Főciklus hiba: {e}")
                await asyncio.sleep(10)

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