import logging
from datetime import datetime, timedelta
from typing import Optional, Any, Dict
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, and_
from app.models.security import PendingAction, ActionStatus
from app.models.history import AuditLog, LogSeverity
from app.models.identity import User
from app.models.system_config import SystemParameter

logger = logging.getLogger(__name__)

class SecurityService:
    
    @staticmethod
    async def get_sec_config(db: AsyncSession) -> Dict[str, Any]:
        """Lekéri a biztonsági korlátokat a központi rendszerparaméterekből."""
        keys = ["SECURITY_MAX_RECORDS_PER_HOUR", "SECURITY_DUAL_CONTROL_ENABLED"]
        stmt = select(SystemParameter).where(SystemParameter.key.in_(keys))
        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"
        }

    # --- 1. SZINT: AUDIT & LOGGING (A Mindenlátó Szem) ---
    async def log_event(
        self, 
        db: AsyncSession, 
        user_id: Optional[int], 
        action: str, 
        severity: LogSeverity, 
        old_data: Optional[Dict] = None, 
        new_data: Optional[Dict] = None, 
        ip: Optional[str] = None, 
        ua: Optional[str] = None, 
        target_type: Optional[str] = None, 
        target_id: Optional[str] = None,
        reason: Optional[str] = None
    ):
        """Minden rendszerművelet rögzítése és azonnali biztonsági elemzése."""
        new_log = AuditLog(
            user_id=user_id,
            severity=severity,
            action=action,
            target_type=target_type,
            target_id=target_id,
            old_data=old_data,
            new_data=new_data,
            ip_address=ip,
            user_agent=ua
        )
        db.add(new_log)
        
        # Ha a szint EMERGENCY, azonnal lőjük le a júzert
        if severity == LogSeverity.emergency:
            await self._execute_emergency_lock(db, user_id, f"Auto-lock triggered by: {action}")
        
        await db.commit()

    # --- 2. SZINT: PENDING ACTIONS (Négy szem elv) ---
    async def request_action(
        self, 
        db: AsyncSession, 
        requester_id: int, 
        action_type: str, 
        payload: Dict, 
        reason: str
    ):
        """Kritikus művelet kezdeményezése jóváhagyásra (nem hajtódik végre azonnal)."""
        new_action = PendingAction(
            requester_id=requester_id,
            action_type=action_type,
            payload=payload,
            reason=reason,
            status=ActionStatus.pending
        )
        db.add(new_action)
        
        await self.log_event(
            db, requester_id, 
            action=f"REQUEST_{action_type}", 
            severity=LogSeverity.critical,
            new_data=payload,
            reason=f"Approval requested: {reason}"
        )
        
        await db.commit()
        return new_action

    async def approve_action(self, db: AsyncSession, approver_id: int, action_id: int):
        """Művelet végrehajtása egy második admin által."""
        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("A művelet nem található vagy már feldolgozták.")
            
        if action.requester_id == approver_id:
            raise Exception("Önmagad kérését nem hagyhatod jóvá! (Négy szem elv)")

        # ITT TÖRTÉNIK A TÉNYLEGES ÜZLETI LOGIKA (Példa: Rangmódosítás)
        if action.action_type == "CHANGE_ROLE":
            user_id = action.payload.get("user_id")
            new_role = action.payload.get("new_role")
            
            user_stmt = select(User).where(User.id == user_id)
            user = (await db.execute(user_stmt)).scalar_one_or_none()
            if user:
                user.role = new_role
                logger.info(f"Role for user {user_id} changed to {new_role} via approved action {action_id}")

        action.status = ActionStatus.approved
        action.approver_id = approver_id
        action.processed_at = func.now()
        
        await self.log_event(
            db, approver_id, 
            action=f"APPROVE_{action.action_type}", 
            severity=LogSeverity.info,
            target_id=str(action.id),
            reason=f"Approved action requested by {action.requester_id}"
        )
        
        await db.commit()
        return True

    # --- 3. SZINT: DATA THROTTLING & EMERGENCY LOCK ---
    async def check_data_access_limit(self, db: AsyncSession, user_id: int):
        """Figyeli a tömeges adatlekérést (Adatlopás elleni védelem)."""
        config = await self.get_sec_config(db)
        one_hour_ago = datetime.now() - timedelta(hours=1)
        
        # Megszámoljuk az utolsó egy óra GET (lekérési) logjait
        stmt = select(func.count(AuditLog.id)).where(
            and_(
                AuditLog.user_id == user_id,
                AuditLog.timestamp >= one_hour_ago,
                AuditLog.action.like("GET_%")
            )
        )
        count = (await db.execute(stmt)).scalar() or 0
        
        if count > config["max_records"]:
            await self.log_event(
                db, user_id, 
                action="MASS_DATA_ACCESS_DETECTED", 
                severity=LogSeverity.emergency,
                reason=f"Access count: {count} (Limit: {config['max_records']})"
            )
            # A log_event automatikusan hívja a _execute_emergency_lock-ot
            return False
        return True

    async def _execute_emergency_lock(self, db: AsyncSession, user_id: int, reason: str):
        """Azonnali fiókfelfüggesztés vészhelyzet esetén."""
        if not user_id: return
        
        stmt = select(User).where(User.id == user_id)
        user = (await db.execute(stmt)).scalar_one_or_none()
        
        if user:
            user.is_active = False
            logger.critical(f"🚨 SECURITY EMERGENCY LOCK: User {user_id} suspended. Reason: {reason}")
            # Itt lehetne bekötni egy külső SMS/Slack/Email riasztást

security_service = SecurityService()