"""
Rate Limiter — ограничение частоты сообщений (анти-спам)
"""
import logging
from datetime import datetime, timedelta
from typing import Dict, List, Tuple, Optional
from sqlalchemy import select, func, delete
from sqlalchemy.ext.asyncio import AsyncSession

logger = logging.getLogger(__name__)


class RateLimiter:
    """Сервис ограничения частоты сообщений"""

    def __init__(self, session: AsyncSession):
        self.session = session
        self.config = self._get_default_config()

    def _get_default_config(self) -> Dict:
        """Конфигурация по умолчанию"""
        return {
            'max_messages': 10,        # Максимум сообщений
            'period_seconds': 60,      # За период (секунд)
            'mute_duration_minutes': 30,  # Длительность мута
            'warnings_before_mute': 2,    # Предупреждения перед мутом
            'exclude_admins': True,       # Исключить админов
            'exclude_verified': False,    # Исключить верифицированных
        }

    async def check_rate_limit(self, user_id: int) -> Tuple[bool, Optional[int]]:
        """
        Проверить лимит сообщений для пользователя
        
        Returns:
            (is_limited, messages_count) — превышен ли лимит и текущее кол-во
        """
        from database.models import MessageRate
        
        # Получаем временное окно
        period_start = datetime.utcnow() - timedelta(seconds=self.config['period_seconds'])
        
        # Считаем сообщения за период
        stmt = (
            select(func.count(MessageRate.id))
            .where(MessageRate.user_id == user_id)
            .where(MessageRate.timestamp >= period_start)
        )
        result = await self.session.execute(stmt)
        count = result.scalar() or 0
        
        is_limited = count >= self.config['max_messages']
        
        return is_limited, count

    async def add_message(self, user_id: int):
        """Добавить сообщение в счётчик"""
        from database.models import MessageRate
        
        message_rate = MessageRate(user_id=user_id)
        self.session.add(message_rate)
        
        # Чистим старые записи (старше периода)
        period_start = datetime.utcnow() - timedelta(seconds=self.config['period_seconds'] * 2)
        await self.session.execute(
            delete(MessageRate).where(MessageRate.timestamp < period_start)
        )

    async def get_user_stats(self, user_id: int) -> Dict:
        """Получить статистику пользователя"""
        from database.models import MessageRate, User
        
        # Период
        period_start = datetime.utcnow() - timedelta(seconds=self.config['period_seconds'])
        
        # Сообщения за период
        stmt = (
            select(func.count(MessageRate.id))
            .where(MessageRate.user_id == user_id)
            .where(MessageRate.timestamp >= period_start)
        )
        result = await self.session.execute(stmt)
        messages_count = result.scalar() or 0
        
        # Получаем пользователя
        user = await self.session.get(User, user_id)
        
        return {
            'messages_count': messages_count,
            'max_messages': self.config['max_messages'],
            'period_seconds': self.config['period_seconds'],
            'is_muted': user.is_muted if user else False,
            'mute_until': user.mute_until.isoformat() if user and user.mute_until else None,
            'rate_limit_warnings': user.rate_limit_warnings if user else 0,
        }

    async def get_all_violators(self) -> List[Dict]:
        """Получить всех нарушителей за последний период"""
        from database.models import MessageRate, User
        
        period_start = datetime.utcnow() - timedelta(seconds=self.config['period_seconds'])
        
        stmt = (
            select(
                MessageRate.user_id,
                func.count(MessageRate.id).label('msg_count')
            )
            .where(MessageRate.timestamp >= period_start)
            .group_by(MessageRate.user_id)
            .having(func.count(MessageRate.id) > self.config['max_messages'] / 2)
            .order_by(func.count(MessageRate.id).desc())
            .limit(20)
        )
        result = await self.session.execute(stmt)
        
        violators = []
        for row in result.all():
            user = await self.session.get(User, row.user_id)
            violators.append({
                'user_id': row.user_id,
                'username': user.username if user else None,
                'full_name': user.full_name if user else None,
                'apartment': user.apartment if user else None,
                'messages_count': row.msg_count,
                'is_muted': user.is_muted if user else False,
            })
        
        return violators

    def get_config(self) -> Dict:
        """Получить конфигурацию"""
        return self.config

    def update_config(self, key: str, value):
        """Обновить конфигурацию"""
        if key in self.config:
            self.config[key] = value
            logger.info(f'RateLimiter config updated: {key}={value}')

    async def mute_user(self, user_id: int, duration_minutes: int = None) -> datetime:
        """Замутить пользователя"""
        from database.models import User
        
        if duration_minutes is None:
            duration_minutes = self.config['mute_duration_minutes']
        
        user = await self.session.get(User, user_id)
        if user:
            user.is_muted = True
            user.mute_until = datetime.utcnow() + timedelta(minutes=duration_minutes)
            await self.session.commit()
            
            mute_until = user.mute_until
            logger.info(f'Пользователь {user_id} замучен до {mute_until}')
            return mute_until
        
        return None

    async def unmute_user(self, user_id: int) -> bool:
        """Размутить пользователя"""
        from database.models import User
        
        user = await self.session.get(User, user_id)
        if user:
            user.is_muted = False
            user.mute_until = None
            await self.session.commit()
            
            logger.info(f'Пользователь {user_id} размучен')
            return True
        
        return False

    async def check_mute_expired(self, user_id: int) -> bool:
        """Проверить истёк ли мут"""
        from database.models import User
        
        user = await self.session.get(User, user_id)
        if user and user.is_muted and user.mute_until:
            if datetime.utcnow() >= user.mute_until:
                # Мут истёк — размучиваем
                user.is_muted = False
                user.mute_until = None
                await self.session.commit()
                logger.info(f'Мут пользователя {user_id} истёк')
                return True
        
        return False

    def get_stats(self) -> Dict:
        """Получить статистику"""
        return {
            'max_messages': self.config['max_messages'],
            'period_seconds': self.config['period_seconds'],
            'mute_duration_minutes': self.config['mute_duration_minutes'],
            'warnings_before_mute': self.config['warnings_before_mute'],
        }
