# /opt/docker/dev/service_finder/backend/app/services/security_service.py
import logging
from datetime import datetime, timedelta, timezone
from typing import Optional, Any, Dict
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, and_
from app.models import PendingAction, ActionStatus
from app.models import AuditLog, LogSeverity
from app.models.identity import User
from app.models.system import SystemParameter

logger = logging.getLogger(__name__)

class SecurityService:
    @staticmethod
    async def get_sec_config(db: AsyncSession) -> Dict[str, Any]:
        """ Lekéri a korlátokat a központi system_parameters-ből. """
        stmt = select(SystemParameter).where(SystemParameter.key.in_(["SECURITY_MAX_RECORDS_PER_HOUR", "SECURITY_DUAL_CONTROL_ENABLED"]))
        res = await db.execute(stmt)
        params = {p.key: p.value for p in res.scalars().all()}
        
        return {
            "max_records": int(params.get("SECURITY_MAX_RECORDS_PER_HOUR", 500)),
            "dual_control": str(params.get("SECURITY_DUAL_CONTROL_ENABLED", "true")).lower() == "true"
        }

    async def log_event(self, db: AsyncSession, user_id: Optional[int], action: str, severity: LogSeverity, **kwargs):
        """ LOGIKA MEGŐRIZVE: Audit naplózás + Emergency Lock trigger. """
        new_log = AuditLog(
            user_id=user_id, severity=severity, action=action,
            target_type=kwargs.get("target_type"), target_id=kwargs.get("target_id"),
            old_data=kwargs.get("old_data"), new_data=kwargs.get("new_data"),
            ip_address=kwargs.get("ip"), user_agent=kwargs.get("ua")
        )
        db.add(new_log)
        
        if severity == LogSeverity.emergency:
            await self._execute_emergency_lock(db, user_id, f"Auto-lock by: {action}")
        
        await db.commit()

    async def request_action(self, db: AsyncSession, requester_id: int, action_type: str, payload: Dict, reason: str):
        """ NÉGY SZEM ELV: Jóváhagyási kérelem indítása. """
        new_action = PendingAction(
            requester_id=requester_id, action_type=action_type, 
            payload=payload, reason=reason, status=ActionStatus.pending
        )
        db.add(new_action)
        await db.commit()
        return new_action

    async def approve_action(self, db: AsyncSession, approver_id: int, action_id: int):
        """ Jóváhagyás végrehajtása (Logic Preserved: Ön-jóváhagyás tiltva). """
        stmt = select(PendingAction).where(PendingAction.id == action_id)
        action = (await db.execute(stmt)).scalar_one_or_none()
        
        if not action or action.status != ActionStatus.pending:
            raise Exception("Művelet nem található.")
        if action.requester_id == approver_id:
            raise Exception("Saját kérést nem hagyhatsz jóvá!")

        # Üzleti logika a művelettípus alapján
        if action.action_type == "CHANGE_ROLE":
            target_user = (await db.execute(select(User).where(User.id == action.payload.get("user_id")))).scalar_one_or_none()
            if target_user: target_user.role = action.payload.get("new_role")
        
        elif action.action_type == "SET_VIP":
            target_user = (await db.execute(select(User).where(User.id == action.payload.get("user_id")))).scalar_one_or_none()
            if target_user: target_user.is_vip = action.payload.get("is_vip", True)
        
        elif action.action_type == "WALLET_ADJUST":
            from app.models.identity import Wallet
            wallet = (await db.execute(select(Wallet).where(Wallet.user_id == action.payload.get("user_id")))).scalar_one_or_none()
            if wallet:
                amount = action.payload.get("amount", 0)
                wallet.balance += amount
        
        elif action.action_type == "SOFT_DELETE_USER":
            target_user = (await db.execute(select(User).where(User.id == action.payload.get("user_id")))).scalar_one_or_none()
            if target_user:
                target_user.is_deleted = True
                target_user.is_active = False
        
        # Audit log
        await self.log_event(
            db, user_id=approver_id, action=f"APPROVE_{action.action_type}",
            severity=LogSeverity.info, target_type="PendingAction", target_id=str(action_id),
            new_data={"action_id": action_id, "action_type": action.action_type}
        )

        action.status = ActionStatus.approved
        action.approver_id = approver_id
        action.processed_at = datetime.now(timezone.utc)
        await db.commit()

    async def check_data_access_limit(self, db: AsyncSession, user_id: int):
        """ DATA THROTTLING: Adatlopás elleni védelem. """
        config = await self.get_sec_config(db)
        limit_time = datetime.now(timezone.utc) - timedelta(hours=1)
        
        stmt = select(func.count(AuditLog.id)).where(
            and_(AuditLog.user_id == user_id, AuditLog.timestamp >= limit_time, AuditLog.action.like("GET_%"))
        )
        count = (await db.execute(stmt)).scalar() or 0
        
        if count > config["max_records"]:
            await self.log_event(db, user_id, "MASS_DATA_ACCESS", LogSeverity.emergency, reason=f"Count: {count}")
            return False
        return True

    async def reject_action(self, db: AsyncSession, approver_id: int, action_id: int, reason: str = None):
        """ Művelet elutasítása. """
        stmt = select(PendingAction).where(PendingAction.id == action_id)
        action = (await db.execute(stmt)).scalar_one_or_none()
        
        if not action or action.status != ActionStatus.pending:
            raise Exception("Művelet nem található.")
        if action.requester_id == approver_id:
            raise Exception("Saját kérést nem utasíthatod el!")

        action.status = ActionStatus.rejected
        action.approver_id = approver_id
        action.processed_at = datetime.now(timezone.utc)
        if reason:
            action.reason = f"Elutasítva: {reason}"

        await self.log_event(
            db, user_id=approver_id, action=f"REJECT_{action.action_type}",
            severity=LogSeverity.warning, target_type="PendingAction", target_id=str(action_id),
            new_data={"action_id": action_id, "reason": reason}
        )
        await db.commit()

    async def get_pending_actions(self, db: AsyncSession, user_id: int = None, action_type: str = None):
        """ Függőben lévő műveletek lekérdezése. """
        stmt = select(PendingAction).where(PendingAction.status == ActionStatus.pending)
        if user_id:
            stmt = stmt.where(PendingAction.requester_id == user_id)
        if action_type:
            stmt = stmt.where(PendingAction.action_type == action_type)
        stmt = stmt.order_by(PendingAction.created_at.desc())
        result = await db.execute(stmt)
        return result.scalars().all()

    async def _execute_emergency_lock(self, db: AsyncSession, user_id: int, reason: str):
        if not user_id: return
        user = (await db.execute(select(User).where(User.id == user_id))).scalar_one_or_none()
        if user:
            user.is_active = False
            logger.critical(f"🚨 EMERGENCY LOCK: User {user_id} suspended. Reason: {reason}")

security_service = SecurityService()