# /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, desc
from app.models import UserStats, PointsLedger, UserBadge, Badge
from app.models.identity import User, Wallet
from app.models import FinancialLedger
from app.services.config_service import config # 2.0 Központi konfigurátor

logger = logging.getLogger("Gamification-Service-2.0")

class GamificationService:
    """
    Gamification Service 2.0 - A 'Jövevény' lelke.
    Felelős a pontozásért, szintekért, büntetésekért és a jutalom-kreditekért.
    """

    @staticmethod
    async def award_points(db: AsyncSession, user_id: int, amount: int, reason: str, social_points: int = 0):
        """ Statikus segédfüggvény a Robotok számára az egyszerűbb híváshoz. """
        service = GamificationService()
        return await service.process_activity(db, user_id, xp_amount=amount, social_amount=social_points, reason=reason)

    async def process_activity(
        self, 
        db: AsyncSession, 
        user_id: int, 
        xp_amount: int, 
        social_amount: int, 
        reason: str, 
        is_penalty: bool = False
    ):
        """ A fő folyamat: Pontozás -> Büntetés szűrés -> Szintszámítás -> Kifizetés. """
        try:
            # 1. ADMIN KONFIGURÁCIÓ BETÖLTÉSE
            # Minden paraméter az admin felületről módosítható JSON-ként
            cfg = await config.get_setting(db, "GAMIFICATION_MASTER_CONFIG", default={
                "xp_logic": {"base_xp": 500, "exponent": 1.5},
                "penalty_logic": {
                    "recovery_rate": 0.5, 
                    "thresholds": {"level_1": 100, "level_2": 500, "level_3": 1000},
                    "multipliers": {"L0": 1.0, "L1": 0.5, "L2": 0.1, "L3": 0.0}
                },
                "conversion_logic": {"social_to_credit_rate": 100},
                "level_rewards": {"credits_per_10_levels": 50}
            })

            # 2. FELHASZNÁLÓ ÉS STATISZTIKA ELLENŐRZÉSE
            stats_stmt = select(UserStats).where(UserStats.user_id == user_id)
            stats = (await db.execute(stats_stmt)).scalar_one_or_none()
            
            if not stats:
                stats = UserStats(user_id=user_id, total_xp=0, current_level=1, penalty_points=0)
                db.add(stats)
                await db.flush()

            # 3. BÜNTETŐ LOGIKA (Ha negatív esemény történik)
            if is_penalty:
                return await self._apply_penalty(db, stats, xp_amount, reason, cfg)

            # 4. SZORZÓK ALKALMAZÁSA (Büntetés alatt állók 'bírsága')
            multiplier = await self._calculate_multiplier(stats, cfg)
            if multiplier <= 0:
                logger.warning(f"User {user_id} pontszerzése blokkolva a büntetések 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
                # Büntetés ledolgozás (Recovery)
                if stats.penalty_points > 0:
                    recovery = int(final_xp * cfg["penalty_logic"]["recovery_rate"])
                    stats.penalty_points = max(0, stats.penalty_points - recovery)

                # Új szint számítás hatványfüggvénnyel:
                # $Level = \sqrt[exponent]{\frac{XP}{Base}} + 1$
                xp_cfg = cfg["xp_logic"]
                new_level = int((stats.total_xp / xp_cfg["base_xp"]) ** (1 / xp_cfg["exponent"])) + 1
                
                if new_level > stats.current_level:
                    await self._handle_level_up(db, user_id, stats.current_level, new_level, cfg)
                    stats.current_level = new_level

            # 6. SOCIAL PONT ÉS KREDIT KONVERZIÓ
            final_social = int(social_amount * multiplier)
            if final_social > 0:
                stats.social_points += final_social
                rate = cfg["conversion_logic"]["social_to_credit_rate"]
                
                if stats.social_points >= rate:
                    credits_to_add = stats.social_points // rate
                    stats.social_points %= rate # A maradék pont megmarad
                    await self._add_earned_credits(db, user_id, credits_to_add, "SOCIAL_ACTIVITY_CONVERSION")

            # 7. NAPLÓZÁS
            db.add(PointsLedger(user_id=user_id, points=final_xp, reason=reason))
            
            await db.commit()
            await db.refresh(stats)
            return stats

        except Exception as e:
            await db.rollback()
            logger.error(f"Gamification Error for user {user_id}: {e}")
            raise e

    # --- PRIVÁT SEGÉDFÜGGVÉNYEK ---

    async def _apply_penalty(self, db: AsyncSession, stats: UserStats, amount: int, reason: str, cfg: dict):
        """Büntetőpontok hozzáadása és korlátozási szintek emelése."""
        stats.penalty_points += amount
        th = cfg["penalty_logic"]["thresholds"]
        
        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=stats.user_id, points=0, penalty_change=amount, reason=f"🔴 PENALTY: {reason}"))
        await db.commit()
        return stats

    async def _calculate_multiplier(self, stats: UserStats, cfg: dict) -> float:
        """Kiszámolja a szorzót a jelenlegi büntetési szint alapján."""
        m = cfg["penalty_logic"]["multipliers"]
        if stats.restriction_level == 3: return m["L3"]
        if stats.restriction_level == 2: return m["L2"]
        if stats.restriction_level == 1: return m["L1"]
        return m["L0"]

    async def _handle_level_up(self, db: AsyncSession, user_id: int, old_lvl: int, new_lvl: int, cfg: dict):
        """Szintlépési jutalmak (pl. minden 10. szintnél kredit)."""
        logger.info(f"✨ Level Up: User {user_id} ({old_lvl} -> {new_lvl})")
        if new_lvl % 10 == 0:
            reward = cfg["level_rewards"]["credits_per_10_levels"]
            await self._add_earned_credits(db, user_id, reward, f"LEVEL_{new_lvl}_REWARD")

    async def _add_earned_credits(self, db: AsyncSession, user_id: int, amount: int, reason: str):
        """Kredit jóváírása a Wallet-ben és a pénzügyi naplóban."""
        wallet_stmt = select(Wallet).where(Wallet.user_id == user_id)
        wallet = (await db.execute(wallet_stmt)).scalar_one_or_none()
        if wallet:
            wallet.earned_credits += Decimal(str(amount))
            db.add(FinancialLedger(
                user_id=user_id,
                amount=float(amount),
                transaction_type="GAMIFICATION_CREDIT",
                details={"reason": reason}
            ))

gamification_service = GamificationService()