# /opt/docker/dev/service_finder/backend/app/workers/vehicle/vehicle_robot_4_validator.py
#!/usr/bin/env python3
"""
Robot-4-Validator (Publisher / Gépágyú)

Az MDM csővezeték utolsó eleme. Feladata:
1. Kivesz 50 darab gold_enriched státuszú járművet a VMD táblából (FOR UPDATE SKIP LOCKED)
2. Validálja az alapvető mezőket (make, marketing_name, power_kw, engine_capacity)
3. Ha sikeres, összeállít egy factory_data JSON-t és UPSERT-et végez a vehicle.vehicle_catalog táblába
   (ON CONFLICT ON CONSTRAINT uix_vehicle_catalog_full)
4. Állítja a VMD státuszt published-re
5. Ha sikertelen, manual_review_needed státuszt állít

AI-mentes, tisztán adatbázis logika.
"""

import asyncio
import logging
import sys
import json
from datetime import datetime
from sqlalchemy import text, update, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import AsyncSessionLocal

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

BATCH_SIZE = 50

class VehicleRobot4Validator:
    def __init__(self):
        pass

    async def fetch_gold_enriched_batch(self, db: AsyncSession):
        """
        Lekérdez egy köteget gold_enriched státuszú járművekből.
        FOR UPDATE SKIP LOCKED zárolással, hogy ne dolgozzon többször ugyanazon.
        """
        query = text("""
            SELECT id, make, marketing_name, power_kw, engine_capacity,
                   fuel_type, year_from, trim_level, transmission_type,
                   body_type, specifications, status
            FROM vehicle.vehicle_model_definitions
            WHERE status = 'gold_enriched'
            ORDER BY priority_score DESC NULLS LAST, id ASC
            FOR UPDATE SKIP LOCKED
            LIMIT :batch_size
        """)
        result = await db.execute(query, {"batch_size": BATCH_SIZE})
        rows = result.fetchall()
        return rows

    def validate_vehicle(self, row):
        """
        Pofonegyszerű ellenőrzés minden lekérdezett sornál:
        - Van make és marketing_name?
        - A power_kw > 0 ÉS engine_capacity > 0?
          (Kivéve, ha a fuel_type tartalmazza az "elektr" szót, mert akkor a ccm lehet 0)
        """
        make = row.make
        marketing_name = row.marketing_name
        power_kw = row.power_kw
        engine_capacity = row.engine_capacity
        fuel_type = (row.fuel_type or "").lower()

        # 1. make és marketing_name ellenőrzés
        if not make or not marketing_name:
            logger.warning(f"ID {row.id}: Hiányzó make vagy marketing_name")
            return False, "missing_make_or_name"

        # 2. power_kw ellenőrzés
        if power_kw is None or power_kw <= 0:
            # Elektromos járműveknek lehet 0 power_kw? Nem, az is pozitív kell legyen.
            logger.warning(f"ID {row.id}: Érvénytelen power_kw ({power_kw})")
            return False, "invalid_power"

        # 3. engine_capacity ellenőrzés
        if engine_capacity is None or engine_capacity < 0:
            logger.warning(f"ID {row.id}: Érvénytelen engine_capacity ({engine_capacity})")
            return False, "invalid_engine_capacity"

        # Kivétel: elektromos járműveknél engine_capacity lehet 0
        is_electric = any(x in fuel_type for x in ['electr', 'elektri', 'hydrogen'])
        if not is_electric and engine_capacity == 0:
            logger.warning(f"ID {row.id}: Nem elektromos jármű engine_capacity 0 (fuel: {fuel_type})")
            return False, "zero_engine_capacity_non_electric"

        # 4. fuel_type ellenőrzés (nem kötelező, de legyen valami)
        if not fuel_type or fuel_type == "unknown":
            logger.warning(f"ID {row.id}: Ismeretlen fuel_type")
            # Ez nem buktató, csak figyelmeztetés
            # return False, "unknown_fuel_type"

        # 5. year_from ellenőrzés (opcionális)
        if row.year_from is None or row.year_from <= 1900:
            logger.warning(f"ID {row.id}: Érvénytelen year_from ({row.year_from})")
            # Nem buktató, de lehet, hogy hiányos

        return True, "valid"

    async def publish_to_catalog(self, db: AsyncSession, row):
        """
        Publikálás (Sikeres Validáció):
        - Állít össze egy factory_data JSON objektumot
        - Végez egy UPSERT-et a vehicle.vehicle_catalog táblába
        - Állítja a VMD státuszt published-re
        """
        # Factory_data összeállítása
        factory_data = {
            "trim_level": row.trim_level or "",
            "transmission_type": row.transmission_type or "",
            "body_type": row.body_type or "",
            "specifications": row.specifications or {},
            "source": "robot_4_publisher",
            "published_at": datetime.utcnow().isoformat()
        }

        # UPSERT a vehicle_catalog táblába
        # A constraint: uix_vehicle_catalog_full (make, model, year_from, fuel_type)
        # Megjegyzés: a model mezőbe a marketing_name kerül
        upsert_query = text("""
            INSERT INTO vehicle.vehicle_catalog
                (make, model, year_from, fuel_type, power_kw, engine_capacity, factory_data, master_definition_id)
            VALUES
                (:make, :model, :year_from, :fuel_type, :power_kw, :engine_capacity, :factory_data, :master_definition_id)
            ON CONFLICT ON CONSTRAINT uix_vehicle_catalog_full
            DO UPDATE SET
                power_kw = EXCLUDED.power_kw,
                engine_capacity = EXCLUDED.engine_capacity,
                factory_data = EXCLUDED.factory_data,
                master_definition_id = EXCLUDED.master_definition_id
            RETURNING id
        """)
        params = {
            "make": row.make,
            "model": row.marketing_name,  # A model a marketing_name
            "year_from": row.year_from if row.year_from else 0,
            "fuel_type": row.fuel_type or "Unknown",
            "power_kw": row.power_kw,
            "engine_capacity": row.engine_capacity,
            "factory_data": json.dumps(factory_data),
            "master_definition_id": row.id
        }
        result = await db.execute(upsert_query, params)
        catalog_id = result.scalar()
        logger.info(f"ID {row.id}: Sikeres publikálás a katalógusba (catalog_id: {catalog_id})")

        # VMD státusz frissítése published-re
        update_query = text("""
            UPDATE vehicle.vehicle_model_definitions
            SET status = 'published',
                updated_at = NOW()
            WHERE id = :id
        """)
        await db.execute(update_query, {"id": row.id})
        logger.info(f"ID {row.id}: Státusz frissítve published-re")

    async def mark_for_manual_review(self, db: AsyncSession, row, reason):
        """
        Elutasítás (Sikertelen Validáció):
        - Állítja a VMD státuszt manual_review_needed-re
        """
        update_query = text("""
            UPDATE vehicle.vehicle_model_definitions
            SET status = 'manual_review_needed',
                last_error = :reason,
                updated_at = NOW()
            WHERE id = :id
        """)
        await db.execute(update_query, {"id": row.id, "reason": reason})
        logger.warning(f"ID {row.id}: Átállítva manual_review_needed-re, ok: {reason}")

    async def process_batch(self):
        """
        Feldolgoz egy köteget.
        """
        async with AsyncSessionLocal() as db:
            try:
                # Tranzakció indítása
                await db.execute(text("BEGIN"))
                
                rows = await self.fetch_gold_enriched_batch(db)
                if not rows:
                    logger.info("Nincs gold_enriched státuszú jármű a feldolgozáshoz.")
                    await db.execute(text("COMMIT"))
                    return 0

                logger.info(f"{len(rows)} gold_enriched jármű lekérdezve.")

                published_count = 0
                manual_review_count = 0

                for row in rows:
                    is_valid, reason = self.validate_vehicle(row)
                    if is_valid:
                        await self.publish_to_catalog(db, row)
                        published_count += 1
                    else:
                        await self.mark_for_manual_review(db, row, reason)
                        manual_review_count += 1

                await db.execute(text("COMMIT"))
                logger.info(f"Köteg feldolgozva. Publikálva: {published_count}, Kézi ellenőrzés: {manual_review_count}")
                return published_count

            except Exception as e:
                await db.execute(text("ROLLBACK"))
                logger.error(f"Hiba a köteg feldolgozásában: {e}", exc_info=True)
                raise

    async def run(self, max_iterations=None):
        """
        Futtatja a robotot folyamatosan (daemon mód).
        Ha nincs gold_enriched adat, vár 30 másodpercet, majd újra próbálkozik.
        """
        iteration = 0
        total_published = 0

        while True:
            if max_iterations is not None and iteration >= max_iterations:
                logger.info(f"Elérte a maximális iterációt ({max_iterations}).")
                break

            iteration += 1
            logger.info(f"--- Iteráció {iteration} ---")
            published = await self.process_batch()
            total_published += published

            if published == 0:
                logger.info("Nincs gold_enriched adat. Várakozás 30 másodperc...")
                await asyncio.sleep(30)
                continue  # Ne lépjen ki, hanem folytassa a ciklust

            # Kis szünet a következő köteg előtt
            await asyncio.sleep(1)

        logger.info(f"Robot leállt. Összesen publikálva: {total_published} jármű.")
        return total_published


async def main():
    """
    Fő függvény: indítja a robotot folyamatos módban.
    """
    robot = VehicleRobot4Validator()
    try:
        # Végtelen ciklus (daemon mód)
        total = await robot.run(max_iterations=None)
        logger.info(f"Robot sikeresen lefutott. Publikálva: {total}")
    except Exception as e:
        logger.error(f"Robot futás közben hiba történt: {e}", exc_info=True)
        sys.exit(1)


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