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

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

class DiscoveryEngine:
    """ 
    THOUGHT PROCESS (IPARI ÜZEMMÓD 2.0):
    1. Őrkutya (Watchdog): Megkeresi és kiszabadítja a beragadt feladatokat óránként.
    2. Differential Sync (Különbözeti Szinkron): Csak a hiányzó vagy új modelleket rögzíti, a gold_enriched-eket kihagyja.
    3. Monthly Scheduler: Havonta egyszer tölti le a teljes RDW adatbázist lapozva.
    """
    
    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" # Állapotfájl, hogy Docker újrainduláskor se kezdje elölről azonnal

    @staticmethod
    async def run_watchdog():
        """ 1. FÁZIS: Az Őrkutya (Dead-Letter Queue Manager) """
        logger.info("🐕 Őrkutya: Beragadt feladatok keresése a rendszerben...")
        try:
            async with AsyncSessionLocal() as db:
                # A) Hunter takarítás (visszaállítás pending-re, ha a Hunter lefagyott)
                res1 = await db.execute(text("UPDATE data.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 (processing) visszaállítva 'pending'-re.")

                # B) AI Robotok takarítása (2 órás timeout)
                query2 = text("""
                    UPDATE data.vehicle_model_definitions
                    SET status = CASE
                        WHEN status = 'research_in_progress' THEN 'unverified'
                        WHEN status = 'ai_synthesis_in_progress' THEN 'awaiting_ai_synthesis'
                    END
                    WHERE status IN ('research_in_progress', 'ai_synthesis_in_progress')
                    AND updated_at < NOW() - INTERVAL '2 hours'
                    RETURNING id;
                """)
                res2 = await db.execute(query2)
                ai_resets = len(res2.fetchall())
                if ai_resets > 0:
                    logger.warning(f"🔄 {ai_resets} db beragadt AI feladat visszaállítva.")
                
                await db.commit()
        except Exception as e:
            logger.error(f"❌ Őrkutya hiba: {e}")

    @staticmethod
    async def seed_manual_bootstrap():
        """ 2. FÁZIS: Alapozó adatok rögzítése """
        initial_data = [
            {"make": "AUDI", "model": "A4", "generation": "B8 (2008-2015)"}, # vehicle_class törölve
            {"make": "BMW", "model": "3 SERIES", "generation": "F30 (2012-2019)"}
        ]
        try:
            async with AsyncSessionLocal() as db:
                for item in initial_data:
                    stmt = select(AssetCatalog).where(AssetCatalog.make == item["make"], AssetCatalog.model == item["model"])
                    if not (await db.execute(stmt)).scalar_one_or_none():
                        db.add(AssetCatalog(**item))
                await db.commit()
        except Exception as e:
            logger.warning(f"Manual bootstrap hiba (Ignorálható, ha az adatbázis már tele van): {e}")

    @classmethod
    async def fetch_with_retry(cls, client: httpx.AsyncClient, url: str, params: dict, retries: int = 3):
        """ Hibatűrő HTTP kérés API leállások ellen. """
        for attempt in range(retries):
            try:
                resp = await client.get(url, params=params, headers=cls.HEADERS)
                if resp.status_code == 200:
                    return resp
                elif resp.status_code == 429: 
                    await asyncio.sleep(2 ** attempt)
                else:
                    return None
            except httpx.RequestError:
                if attempt == retries - 1:
                    return None
                await asyncio.sleep(2 ** attempt)
        return None

    @classmethod
    async def seed_from_rdw(cls):
        """ 3. FÁZIS: Távoli felfedezés - KÜLÖNBÖZETI SZINKRONIZÁCIÓ (Differential Sync) """
        logger.info("📥 RDW TÖMEGES LETÖLTÉS: Új modellek keresése (Differential Sync)...")
        
        limit = 10000
        offset = 0
        inserted_count = 0
        updated_count = 0
        
        async with httpx.AsyncClient(timeout=60.0) as client:
            while True:
                params = {
                    "$select": "merk,handelsbenaming,voertuigsoort,count(*) as total",
                    "$group": "merk,handelsbenaming,voertuigsoort",
                    "$order": "total DESC",
                    "$limit": limit,
                    "$offset": offset
                }
                
                resp = await cls.fetch_with_retry(client, "https://opendata.rdw.nl/resource/m9d7-ebf2.json", params)
                if not resp: break
                raw_data = resp.json()
                if not raw_data: break

                logger.info(f"📊 Lapozás: {offset} - {offset + len(raw_data)} tételek analízise...")

                async with AsyncSessionLocal() as db:
                    for entry in raw_data:
                        make = str(entry.get("merk", "")).upper().strip()
                        model = str(entry.get("handelsbenaming", "")).upper().strip()
                        v_kind = entry.get("voertuigsoort", "")
                        total_count = int(entry.get("total", 0))
                        
                        if not make or not model: continue

                        if "Personenauto" in v_kind: v_class = 'car'
                        elif "Motorfiets" in v_kind: v_class = 'motorcycle'
                        else: v_class = 'truck'

                        # A MÁGIA: Különbözeti Szinkronizáció SQL + Explicit Type Casting
                        query = text("""
                            INSERT INTO data.catalog_discovery (make, model, vehicle_class, status, priority_score)
                            SELECT 
                                CAST(:make AS VARCHAR), 
                                CAST(:model AS VARCHAR), 
                                CAST(:v_class AS VARCHAR), 
                                'pending', 
                                :priority
                            WHERE NOT EXISTS (
                                SELECT 1 FROM data.vehicle_model_definitions 
                                WHERE make = CAST(:make AS VARCHAR) 
                                  AND marketing_name = CAST(:model AS VARCHAR) 
                                  AND status = 'gold_enriched'
                            )
                            ON CONFLICT (make, model) 
                            DO UPDATE SET priority_score = EXCLUDED.priority_score
                            WHERE data.catalog_discovery.status != 'processed'
                            RETURNING xmax;
                        """)
                        
                        result = await db.execute(query, {
                            "make": make, "model": model, "v_class": v_class, "priority": total_count
                        })
                        
                        row = result.fetchone()
                        if row:
                            if row[0] == 0: inserted_count += 1 # Új beszúrás
                            else: updated_count += 1            # Meglévő frissítése

                    await db.commit()
                offset += limit
                await asyncio.sleep(1) 
                
        logger.info(f"✅ RDW Szinkron kész! Új modellek a listán: {inserted_count} | Frissített prioritások: {updated_count}")
        
        # Sikeres futás regisztrálása a fájlrendszeren
        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())

    @classmethod
    def should_run_rdw_sync(cls) -> bool:
        """ Ellenőrzi, hogy eltelt-e 30 nap a legutóbbi sikeres RDW szinkronizáció óta. """
        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())
                return datetime.now() - last_sync > timedelta(days=30)
        except Exception:
            return True

    @classmethod
    async def run(cls):
        """ FŐ CIKLUS: Havi ütemező és Óránkénti Őrkutya """
        logger.info("🚀 ÉLES ÜZEM: Discovery Engine (Differential Sync) & Watchdog indítása...")
        await cls.seed_manual_bootstrap()

        while True:
            # 1. Óránkénti takarítás
            await cls.run_watchdog()
            
            # 2. Havi szinkronizáció ellenőrzése
            if cls.should_run_rdw_sync():
                await cls.seed_from_rdw()
            else:
                logger.info("🛌 Az RDW szinkronizáció már lefutott az elmúlt 30 napban. Ugrás...")

            # 3. Alvás 1 órát (Heartbeat)
            logger.info("⏱️ A Discovery Engine most 1 órát pihen a következő Őrkutya futásig.")
            await asyncio.sleep(3600)

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