# /opt/docker/dev/service_finder/backend/app/services/gamification_service.py
import logging
import math
from decimal import Decimal
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.models.gamification import UserStats, PointsLedger
from app.models.identity import User, Wallet
from app.models.audit import FinancialLedger
from app.models.system import SystemParameter

logger = logging.getLogger(__name__)

class GamificationService:
    @staticmethod
    async def get_config(db: AsyncSession):
        """ 
        Dinamikus konfiguráció lekérése. 
        Ha nincs a DB-ben, ezek az alapértelmezett 'szabályok'.
        """
        stmt = select(SystemParameter).where(SystemParameter.key == "GAMIFICATION_MASTER_CONFIG")
        res = await db.execute(stmt)
        param = res.scalar_one_or_none()
        
        return param.value if param else {
            "xp_logic": {"base_xp": 500, "exponent": 1.5},
            "penalty_logic": {
                "thresholds": {"level_1": 100, "level_2": 500, "level_3": 1000},
                "multipliers": {"level_0": 1.0, "level_1": 0.5, "level_2": 0.1, "level_3": 0.0},
                "recovery_rate": 0.5 # Mennyi büntetőpontot dolgoz le 1 XP szerzésekor
            },
            "conversion_logic": {"social_to_credit_rate": 100}, # 100 social pont = 1 credit
            "level_rewards": {"credits_per_10_levels": 50},
            "blocked_roles": ["superadmin", "service_bot"]
        }

    async def process_activity(
        self, 
        db: AsyncSession, 
        user_id: int, 
        xp_amount: int, 
        social_amount: int, 
        reason: str, 
        is_penalty: bool = False
    ):
        """
        A Rendszer 'Bírája'. Ez a függvény kezeli a teljes folyamatot:
        Büntet, jutalmaz, szintet léptet és pénzt vált.
        """
        config = await self.get_config(db)
        
        # 1. Felhasználó ellenőrzése
        user = (await db.execute(select(User).where(User.id == user_id))).scalar_one_or_none()
        if not user or user.is_deleted or user.role in config["blocked_roles"]:
            return None

        # 2. Statisztikák lekérése (vagy létrehozása)
        stats = (await db.execute(select(UserStats).where(UserStats.user_id == user_id))).scalar_one_or_none()
        if not stats:
            stats = UserStats(user_id=user_id)
            db.add(stats)
            await db.flush()

        # 3. BÜNTETŐ LOGIKA (Ha rosszalkodott a user)
        if is_penalty:
            stats.penalty_points += xp_amount
            th = config["penalty_logic"]["thresholds"]
            
            # Korlátozási szintek beállítása
            if stats.penalty_points >= th["level_3"]: stats.restriction_level = 3
            elif stats.penalty_points >= th["level_2"]: stats.restriction_level = 2
            elif stats.penalty_points >= th["level_1"]: stats.restriction_level = 1
            
            db.add(PointsLedger(user_id=user_id, points=0, penalty_change=xp_amount, reason=f"🔴 BÜNTETÉS: {reason}"))
            await db.commit()
            return stats

        # 4. SZORZÓK ALKALMAZÁSA (Büntetés alatt kevesebb pont jár)
        multiplier = config["penalty_logic"]["multipliers"].get(f"level_{stats.restriction_level}", 1.0)
        if multiplier <= 0:
            logger.warning(f"User {user_id} tevékenysége blokkolva a magas büntetés miatt.")
            return stats

        # 5. XP SZÁMÍTÁS ÉS SZINTLÉPÉS
        final_xp = int(xp_amount * multiplier)
        if final_xp > 0:
            stats.total_xp += final_xp
            
            # Ledolgozás: Az XP szerzés csökkenti a meglévő büntetőpontokat
            if stats.penalty_points > 0:
                rec = int(final_xp * config["penalty_logic"]["recovery_rate"])
                stats.penalty_points = max(0, stats.penalty_points - rec)

            # Szint kiszámítása logaritmikus görbe alapján
            xp_cfg = config["xp_logic"]
            new_level = int((stats.total_xp / xp_cfg["base_xp"]) ** (1/xp_cfg["exponent"])) + 1
            
            if new_level > stats.current_level:
                # Kerek szinteknél jutalom (pl. minden 10. szint)
                if new_level % 10 == 0:
                    reward = config["level_rewards"]["credits_per_10_levels"]
                    await self._add_earned_credits(db, user_id, reward, f"Szint bónusz: {new_level}")
                stats.current_level = new_level

        # 6. SOCIAL PONT ÉS VALUTA VÁLTÁS (Kredit generálás)
        final_social = int(social_amount * multiplier)
        if final_social > 0:
            stats.social_points += final_social
            rate = config["conversion_logic"]["social_to_credit_rate"]
            
            if stats.social_points >= rate:
                new_credits = stats.social_points // rate
                stats.social_points %= rate # A maradék megmarad
                await self._add_earned_credits(db, user_id, new_credits, "Közösségi aktivitás váltása")

        # 7. NAPLÓZÁS (A PointsLedger a forrása a ranglistának)
        db.add(PointsLedger(
            user_id=user_id, 
            points=final_xp, 
            reason=reason
        ))
        
        await db.commit()
        await db.refresh(stats)
        return stats

    async def _add_earned_credits(self, db: AsyncSession, user_id: int, amount: int, reason: str):
        """ Kredit hozzáadása a Wallethez és a Pénzügyi Főkönyvhöz (FinancialLedger). """
        wallet = (await db.execute(select(Wallet).where(Wallet.user_id == user_id))).scalar_one_or_none()
        if wallet:
            wallet.earned_credits += Decimal(str(amount))
            # Pénzügyi audit bejegyzés
            db.add(FinancialLedger(
                user_id=user_id,
                amount=float(amount),
                currency="HUF",
                transaction_type="GAMIFICATION_REWARD",
                details={"reason": reason}
            ))

gamification_service = GamificationService()