import asyncio
import httpx
import logging
import os
import sys
from datetime import datetime, timedelta
from sqlalchemy import text
from app.database import AsyncSessionLocal

# Szigorú naplózás
logging.basicConfig(level=logging.INFO, format='%(asctime)s [R0-DISCOVERY] %(message)s', stream=sys.stdout)
logger = logging.getLogger("Robot-0")

class DiscoveryEngine:
    """
    Vehicle Robot 0 v3.0: A Nagy Stratéga
    Feladata: Végiglapozza az RDW teljes adatbázisát (autó, motor, teherautó),
    kigyűjti az összes létező márka+modell kombinációt, és darabszám alapján
    priorizálja őket a catalog_discovery táblában a vadászok (Hunterek) számára.
    """
    RDW_API = "https://opendata.rdw.nl/resource/m9d7-ebf2.json"
    RDW_TOKEN = os.getenv("RDW_APP_TOKEN")
    HEADERS = {"X-App-Token": RDW_TOKEN} if RDW_TOKEN else {}
    SYNC_STATE_FILE = "/app/temp/.last_rdw_sync"
    BATCH_LIMIT = 10000 # RDW API maximum limit aggregálásnál

    CATEGORIES = [
        {"name": "car", "rdw_types": ["'Personenauto'"]},
        {"name": "motorcycle", "rdw_types": ["'Motorfiets'"]},
        {"name": "truck", "rdw_types": ["'Bedrijfsauto'", "'Vrachtwagen'", "'Opleggertrekker'"]}
    ]

    @classmethod
    async def fetch_with_retry(cls, client: httpx.AsyncClient, params: dict, retries: int = 3):
        for attempt in range(retries):
            try:
                resp = await client.get(cls.RDW_API, params=params, headers=cls.HEADERS)
                if resp.status_code == 200:
                    return resp.json()
                elif resp.status_code == 429:
                    await asyncio.sleep(2 ** attempt)
                else:
                    logger.warning(f"RDW API Hiba: {resp.status_code}")
                    return None
            except httpx.RequestError as e:
                if attempt == retries - 1:
                    logger.error(f"Hálózati hiba: {e}")
                    return None
                await asyncio.sleep(2 ** attempt)
        return None

    @classmethod
    async def process_category(cls, db, v_class: str, rdw_types: list):
        """ Egy adott kategória (pl. autók) teljes végiglapozása és mentése. """
        type_filter = " OR ".join([f"voertuigsoort = {t}" for t in rdw_types])
        offset = 0
        total_inserted = 0
        total_updated = 0

        logger.info(f"🔍 {v_class.upper()} kategória elemzésének indítása...")

        async with httpx.AsyncClient(timeout=60.0) as client:
            while True:
                # Az aggregált SQL lekérdezés, amit az RDW API-nak küldünk
                params = {
                    "$select": "merk, handelsbenaming, count(*) AS darabszam",
                    "$where": type_filter,
                    "$group": "merk, handelsbenaming",
                    "$order": "darabszam DESC",
                    "$limit": cls.BATCH_LIMIT,
                    "$offset": offset
                }

                data = await cls.fetch_with_retry(client, params)
                if not data: 
                    break # Ha üres a válasz, végeztünk a kategóriával

                logger.info(f"📊 {v_class.upper()}: Feldolgozás {offset} - {offset + len(data)}...")

                # Mivel ez tömeges mentés, egy közös tranzakciót használunk
                for item in data:
                    make_name = str(item.get("merk", "")).upper().strip()
                    model_name = str(item.get("handelsbenaming", "")).upper().strip()
                    if not make_name or not model_name: 
                        continue
                    
                    count = int(item.get("darabszam", 0))

                    try:
                        async with db.begin_nested():
                            # Ha még nincs ilyen (vagy ha van, frissítjük a prioritást)
                            query = text("""
                                INSERT INTO vehicle.catalog_discovery (make, model, vehicle_class, status, source, attempts, priority_score)
                                VALUES (:make, :model, :class, 'pending', 'STRATEGIST-V3', 0, :score)
                                ON CONFLICT (make, model, vehicle_class)
                                DO UPDATE SET priority_score = GREATEST(vehicle.catalog_discovery.priority_score, :score)
                                WHERE vehicle.catalog_discovery.status != 'processed'
                                RETURNING xmax;
                            """)
                            res = await db.execute(query, {"make": make_name, "model": model_name, "class": v_class, "score": count})
                            
                            # Logika a statisztikához: xmax = 0 ha új beszúrás, > 0 ha update
                            row = res.fetchone()
                            if row:
                                if row[0] == 0: total_inserted += 1
                                else: total_updated += 1

                    except Exception as e:
                        logger.warning(f"⚠️ Hiba a mentésnél ({make_name} {model_name}): {e}")

                await db.commit()
                
                # Ha kevesebb adat jött vissza, mint a limit, akkor elértük az utolsó oldalt
                if len(data) < cls.BATCH_LIMIT:
                    break
                
                offset += cls.BATCH_LIMIT
                await asyncio.sleep(1) # API kímélése

        logger.info(f"✅ {v_class.upper()} kész! Új felfedezett: {total_inserted} | Frissített prioritás: {total_updated}")

    @classmethod
    async def run_watchdog(cls):
        """ Kiszabadítja azokat a Hunter feladatokat, amiknél a szerver esetleg újraindult. """
        logger.info("🐕 Őrkutya: Beragadt feladatok ellenőrzése...")
        try:
            async with AsyncSessionLocal() as db:
                res1 = await db.execute(text("UPDATE vehicle.catalog_discovery SET status = 'pending' WHERE status = 'processing' RETURNING id;"))
                hunter_resets = len(res1.fetchall())
                if hunter_resets > 0:
                    logger.warning(f"🔄 {hunter_resets} db beragadt Hunter feladat visszaállítva.")

                res2 = await db.execute(text("""
                    UPDATE vehicle.vehicle_model_definitions
                    SET status = 'unverified'
                    WHERE status IN ('research_in_progress', 'ai_synthesis_in_progress')
                    AND updated_at < NOW() - INTERVAL '2 hours'
                    RETURNING id;
                """))
                ai_resets = len(res2.fetchall())
                if ai_resets > 0:
                    logger.warning(f"🔄 {ai_resets} db beragadt AI/Kutató feladat visszaállítva.")
                await db.commit()
        except Exception as e:
            logger.error(f"❌ Őrkutya hiba: {e}")

    @classmethod
    def should_run_rdw_sync(cls) -> bool:
        if not os.path.exists(cls.SYNC_STATE_FILE): return True
        try:
            with open(cls.SYNC_STATE_FILE, 'r') as f:
                last_sync = datetime.fromisoformat(f.read().strip())
                # Ha elmúlt 7 nap, újra felfedezi az RDW-t
                return datetime.now() - last_sync > timedelta(days=7)
        except Exception:
            return True

    @classmethod
    async def run(cls):
        logger.info("🚀 Robot 0 (Strategist & Discovery) ONLINE")
        
        # 1. Adatbázis séma biztosítása a priority_score-hoz
        async with AsyncSessionLocal() as db:
            try:
                await db.execute(text("ALTER TABLE vehicle.catalog_discovery ADD COLUMN IF NOT EXISTS priority_score INTEGER DEFAULT 0;"))
                await db.commit()
            except Exception as e:
                await db.rollback()
                logger.error(f"⚠️ Séma hiba (ignorálható): {e}")

        while True:
            await cls.run_watchdog()
            
            if cls.should_run_rdw_sync():
                logger.info("🌍 Teljes RDW Hálózat Letapogatás Indul...")
                async with AsyncSessionLocal() as db:
                    for category in cls.CATEGORIES:
                        await cls.process_category(db, category["name"], category["rdw_types"])
                
                os.makedirs(os.path.dirname(cls.SYNC_STATE_FILE), exist_ok=True)
                with open(cls.SYNC_STATE_FILE, 'w') as f:
                    f.write(datetime.now().isoformat())
                logger.info("🏁 Letapogatás befejezve. Alvás a következő ellenőrzésig.")
            else:
                logger.info("🛌 Az RDW szinkronizáció már lefutott a héten. Őrködés folytatása...")

            await asyncio.sleep(3600) # Óránként ellenőrzi, kell-e valamit tenni

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