# /opt/docker/dev/service_finder/backend/app/workers/service/service_robot_5_auditor.py
import asyncio
import logging
import json
import random
from datetime import datetime
from sqlalchemy import select, text, update, insert
from sqlalchemy.dialects.postgresql import insert as pg_insert
from app.database import AsyncSessionLocal

# MB 2.0: Közvetlen és teljes importok a hiánytalan működéshez
from app.models.marketplace.service import ServiceStaging, ServiceProfile, ExpertiseTag, ServiceExpertise
from app.models.marketplace.organization import Organization
from app.models.identity.identity import User, Person
from app.models.gamification.gamification import UserContribution, PointsLedger, UserStats
from app.models.system.system import SystemParameter
from app.core.config import settings

# --- NAPLÓZÁS KONFIGURÁCIÓ ---
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] Service-Robot-5-Auditor: %(message)s')
logger = logging.getLogger("Service-Robot-5-Auditor")

class ServiceAuditor:
    """ 
    Service Robot 5: Auditor és Publikáló (Staging → Production) 
    Verzió: 1.3 - Tömörítetlen, teljes adatstruktúra szinkronnal és ADAPTÍV időzítéssel.
    """

    @staticmethod
    async def get_trust_threshold(db) -> int:
        """ Lekéri a SystemParameter-ből a trust score küszöböt a validáláshoz. """
        try:
            query = select(SystemParameter).where(
                SystemParameter.key == "service_trust_threshold"
            )
            result = await db.execute(query)
            param = result.scalar_one_or_none()
            
            if param and param.value:
                logger.info(f"🔍 Rendszer trust küszöb értéke: {param.value}")
                return int(param.value)
        except Exception as e:
            logger.warning(f"⚠️ Trust threshold lekérdezés hiba, alapértelmezett 70 használata: {e}")
        
        return 70

    @staticmethod
    async def create_digital_twin(db, staging_data: dict) -> int:
        """
        Létrehoz vagy megkeres egy Digital Twin (Organization) entitást.
        A 'fleet' sémában lévő organizations táblát kezeli.
        """
        try:
            tax_no = staging_data.get("tax_number")
            org_name = staging_data.get("name", "").strip()
            existing_org = None

            # 1. Ellenőrzés adószám alapján (ha rendelkezésre áll)
            if tax_no:
                logger.info(f"🔎 Digital Twin keresése adószám alapján: {tax_no}")
                tax_query = select(Organization).where(
                    Organization.tax_number == tax_no.strip(),
                    Organization.is_deleted == False
                )
                tax_result = await db.execute(tax_query)
                existing_org = tax_result.scalar_one_or_none()

            # 2. Ellenőrzés név alapján (ha az adószám nem talált egyezést)
            if not existing_org and org_name:
                logger.info(f"🔎 Digital Twin keresése név alapján: {org_name}")
                org_query = select(Organization).where(
                    Organization.name == org_name,
                    Organization.is_deleted == False
                )
                name_result = await db.execute(org_query)
                existing_org = name_result.scalar_one_or_none()
            
            if existing_org:
                logger.info(f"✅ Meglévő Digital Twin azonosítva: {existing_org.name} (ID: {existing_org.id})")
                return existing_org.id
            
            # 3. Új Organization (Digital Twin) létrehozása
            new_org = Organization(
                name=org_name,
                full_name=staging_data.get("full_name") or org_name,
                tax_number=tax_no,
                reg_number=staging_data.get("registration_number"),
                contact_email=staging_data.get("contact_email"),
                contact_phone=staging_data.get("contact_phone"),
                website=staging_data.get("website"),
                address_zip=staging_data.get("postal_code"),
                address_city=staging_data.get("city"),
                address_street_name=staging_data.get("address_line1"),
                country_code=staging_data.get("country_code", "HU"),
                is_active=True,
                status="active",
                created_at=datetime.utcnow(),
                updated_at=datetime.utcnow()
            )
            
            db.add(new_org)
            await db.flush() 
            await db.refresh(new_org)
            
            logger.info(f"✨ Új Digital Twin (Organization) létrehozva: {new_org.name}")
            return new_org.id
            
        except Exception as e:
            logger.error(f"❌ Digital Twin hiba: {e}")
            raise

    @staticmethod
    async def create_service_profile(db, staging_data: dict, org_id: int) -> int:
        """ Létrehozza az éles ServiceProfile rekordot a marketplace sémában. """
        try:
            new_service = ServiceProfile(
                organization_id=org_id,
                name=staging_data.get("name", "").strip(),
                description=staging_data.get("description") or "",
                contact_email=staging_data.get("contact_email"),
                contact_phone=staging_data.get("contact_phone"),
                website=staging_data.get("website"),
                address_line1=staging_data.get("address_line1"),
                address_line2=staging_data.get("address_line2"),
                city=staging_data.get("city"),
                postal_code=staging_data.get("postal_code"),
                country_code=staging_data.get("country_code", "HU"),
                latitude=staging_data.get("latitude"),
                longitude=staging_data.get("longitude"),
                trust_score=staging_data.get("trust_score", 0),
                status="active",
                external_id=staging_data.get("external_id"),
                metadata=staging_data.get("metadata") or {},
                created_at=datetime.utcnow(),
                updated_at=datetime.utcnow()
            )
            
            db.add(new_service)
            await db.flush()
            await db.refresh(new_service)
            
            logger.info(f"✅ Éles ServiceProfile rögzítve: {new_service.name} (ID: {new_service.id})")
            return new_service.id
        except Exception as e:
            logger.error(f"❌ ServiceProfile rögzítési hiba: {e}")
            raise

    @staticmethod
    async def award_user_contribution(db, user_id: int, service_id: int, staging_id: int):
        """ XP és pontok kiosztása a felhasználónak. """
        try:
            # 1. Aktuális aktív szezon keresése
            season_query = text("""
                SELECT id FROM system.seasons 
                WHERE is_active = true 
                AND start_date <= CURRENT_DATE 
                AND end_date >= CURRENT_DATE
                LIMIT 1
            """)
            result = await db.execute(season_query)
            season_row = result.fetchone()
            season_id = season_row[0] if season_row else None
            
            # 2. UserContribution rekord létrehozása
            contribution = UserContribution(
                user_id=user_id,
                season_id=season_id,
                contribution_type="service_submission",
                entity_type="service",
                entity_id=service_id,
                points_awarded=50,
                xp_awarded=100,
                status="approved",
                metadata={
                    "staging_id": staging_id,
                    "awarded_at": datetime.utcnow().isoformat(),
                    "reason": "Auditor publication approval"
                },
                created_at=datetime.utcnow()
            )
            db.add(contribution)
            
            # 3. UserStats (globális statisztika) frissítése
            stats_query = select(UserStats).where(UserStats.user_id == user_id)
            stats_result = await db.execute(stats_query)
            user_stats = stats_result.scalar_one_or_none()
            
            if user_stats:
                user_stats.total_points += 50
                user_stats.total_xp += 100
                user_stats.services_submitted += 1
                user_stats.updated_at = datetime.utcnow()
            else:
                new_stats = UserStats(
                    user_id=user_id, total_points=50, total_xp=100,
                    services_submitted=1, created_at=datetime.utcnow()
                )
                db.add(new_stats)
            
            # 4. PointsLedger bejegyzés
            ledger = PointsLedger(
                user_id=user_id, points=50, xp=100,
                source_type="service_submission",
                source_id=service_id,
                description="Reward for verified service publication",
                created_at=datetime.utcnow()
            )
            db.add(ledger)
            
            logger.info(f"🏆 Jutalmazás elvégezve: User {user_id} (+50 PT, +100 XP)")
        except Exception as e:
            logger.error(f"⚠️ Hiba a jutalmazási folyamatban: {e}")

    @classmethod
    async def process_staging_record(cls, db, staging_id: int):
        """ Egyetlen staging rekord teljes körű feldolgozása tranzakcióban. """
        try:
            # 1. Rekord lekérése
            query = select(ServiceStaging).where(
                ServiceStaging.id == staging_id,
                ServiceStaging.status == 'auditing'
            )
            result = await db.execute(query)
            staging = result.scalar_one_or_none()
            
            if not staging:
                logger.error(f"❌ Staging rekord nem található vagy rossz státuszban van: {staging_id}")
                return False
            
            # 2. Trust Score ellenőrzés
            trust_threshold = await cls.get_trust_threshold(db)
            if staging.trust_score < trust_threshold:
                logger.warning(f"🚫 Trust Score elégtelen: {staging.trust_score} < {trust_threshold}")
                staging.status = 'rejected'
                staging.rejection_reason = f'Low trust score ({staging.trust_score})'
                staging.updated_at = datetime.utcnow()
                await db.commit()
                return False
            
            # 3. Adatok kigyűjtése explicit módon
            staging_data = {
                "name": staging.name,
                "description": staging.description,
                "contact_email": staging.contact_email,
                "contact_phone": staging.contact_phone,
                "website": staging.website,
                "address_line1": staging.address_line1,
                "address_line2": staging.address_line2,
                "city": staging.city,
                "postal_code": staging.postal_code,
                "country_code": staging.country_code,
                "latitude": staging.latitude,
                "longitude": staging.longitude,
                "trust_score": staging.trust_score,
                "external_id": staging.external_id,
                "metadata": staging.metadata or {},
                "tax_number": staging.metadata.get("tax_number") if staging.metadata else None,
                "registration_number": staging.metadata.get("registration_number") if staging.metadata else None
            }
            
            # 4. Digital Twin (Cég) fázis
            org_id = await cls.create_digital_twin(db, staging_data)
            
            # 5. Production (Szolgáltatás) fázis
            service_id = await cls.create_service_profile(db, staging_data, org_id)
            
            # 6. Gamification fázis
            if staging.submitted_by:
                await cls.award_user_contribution(db, staging.submitted_by, service_id, staging_id)
            
            # 7. Lezárás és Audit Trail mentése
            staging.status = 'published'
            staging.published_at = datetime.utcnow()
            staging.service_profile_id = service_id
            staging.organization_id = org_id
            staging.updated_at = datetime.utcnow()
            staging.audit_trail = {
                "audited_by": "robot_5",
                "audited_at": datetime.utcnow().isoformat(),
                "trust_threshold_used": trust_threshold,
                "final_trust_score": staging.trust_score,
                "organization_id": org_id,
                "service_profile_id": service_id,
                "version": "1.3"
            }
            
            await db.commit()
            logger.info(f"✅ SIKER: Staging {staging_id} -> Production {service_id}")
            return True
            
        except Exception as e:
            logger.error(f"❌ Kritikus feldolgozási hiba (Staging ID: {staging_id}): {e}")
            await db.rollback()
            return False

    @classmethod
    async def run_worker(cls):
        """ 
        Az Auditor fő folyamata: 
        Adaptív ciklus: 20mp ha van adat, 5 perc ha 5x üres. 
        """
        logger.info("🚀 Service Auditor v1.3 ONLINE - Adaptív üzemmód")
        empty_counter = 0
        
        while True:
            try:
                async with AsyncSessionLocal() as db:
                    # 1. Következő rekord lefoglalása atomi módon
                    query = text("""
                        UPDATE marketplace.service_staging
                        SET status = 'auditing'
                        WHERE id = (
                            SELECT id FROM marketplace.service_staging
                            WHERE status = 'auditor_ready'
                            AND trust_score >= (
                                SELECT COALESCE(
                                    (SELECT value::integer FROM system.system_parameters 
                                     WHERE key = 'service_trust_threshold'),
                                    70
                                )
                            )
                            FOR UPDATE SKIP LOCKED
                            LIMIT 1
                        )
                        RETURNING id
                    """)
                    
                    result = await db.execute(query)
                    row = result.fetchone()
                    
                    if not row:
                        empty_counter += 1
                        if empty_counter >= 5:
                            sleep_time = 600 # 5 perc várakozás
                            logger.info(f"💤 Nincs adat (5x üres). Lassítás {sleep_time} másodpercre (5 perc)...")
                        else:
                            sleep_time = 20 # 20 másodperc várakozás
                            logger.info(f"⏳ Várólista üres, következő próba {sleep_time} mp múlva. (Próba: {empty_counter}/5)")
                        
                        await db.commit()
                        await asyncio.sleep(sleep_time)
                        continue
                    
                    # Ha találtunk adatot:
                    empty_counter = 0
                    staging_id = row[0]
                    await db.commit() # Elengedjük a zárolást a hosszas feldolgozáshoz
                    
                    logger.info(f"🎯 Auditor feldolgozás indítása: staging_id={staging_id}")
                    
                    # 2. Rekord tényleges feldolgozása egy friss session-ben
                    async with AsyncSessionLocal() as process_db:
                        await cls.process_staging_record(process_db, staging_id)
                    
                    # 3. Sikeres feldolgozás utáni pihenő az utasítás szerint (20 mp)
                    await asyncio.sleep(20)
                    
            except Exception as e:
                logger.error(f"❌ Auditor fő ciklus hiba: {e}")
                await asyncio.sleep(10)

async def main():
    """ Belépési pont a konténer számára. """
    auditor = ServiceAuditor()
    await auditor.run_worker()

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