"""
Детектор шпионов - анализ активности пользователей
"""
import json
import logging
from datetime import datetime, timedelta
from typing import List, Dict, Tuple
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from database.models import User, Message, SpyLog
from config import ADMIN_USER_ID

logger = logging.getLogger(__name__)


class SpyDetector:
    """Детектор подозрительной активности"""
    
    def __init__(self, session: AsyncSession):
        self.session = session
        self.patterns = self._load_patterns()
    
    def _load_patterns(self) -> Dict:
        """Загрузка паттернов из JSON"""
        try:
            with open('data/spies_patterns.json', 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            logger.error(f'Не удалось загрузить паттерны: {e}')
            return self._get_default_patterns()
    
    def _get_default_patterns(self) -> Dict:
        """Паттерны по умолчанию"""
        return {
            'patterns': {
                'new_account_days': 7,
                'no_avatar_score': 10,
                'generic_username_score': 15,
                'unverified_hours': 24,
                'unverified_score': 25,
                'provocation_score': 30,
                'office_hours_score': 15,
                'multicount_score': 50,
            },
            'thresholds': {
                'normal': 30,
                'suspicious': 60,
            },
            'office_hours': {
                'start': 9,
                'end': 18,
                'weekdays': [0, 1, 2, 3, 4],
            }
        }
    
    async def analyze_user(self, user: User) -> Tuple[int, List[str]]:
        """
        Анализ пользователя на подозрительность
        Возвращает: (score, list_of_flags)
        """
        score = 0
        flags = []
        patterns = self.patterns['patterns']
        
        # 1. Новый аккаунт
        # Примечание: Telegram не отдаёт дату создания аккаунта через Bot API
        # Можно эвристически определять по первым сообщениям
        
        # 2. Нет аватарки (проверяем по наличию username/фото)
        if not user.username or user.username.startswith('user'):
            score += patterns.get('no_avatar_score', 10)
            flags.append('no_avatar')
        
        # 3. Стандартный никнейм
        if self._is_generic_username(user.username):
            score += patterns.get('generic_username_score', 15)
            flags.append('generic_username')
        
        # 4. Не прошёл верификацию
        if not user.verified:
            hours_since_join = (datetime.utcnow() - user.join_date).total_seconds() / 3600
            if hours_since_join > patterns.get('unverified_hours', 24):
                score += patterns.get('unverified_score', 25)
                flags.append('unverified')
        
        # 5. Активность только в рабочие часы
        is_office = await self._check_office_hours_activity(user.user_id)
        if is_office:
            score += patterns.get('office_hours_score', 15)
            flags.append('office_hours')
        
        # 6. Провокационные сообщения
        has_provocation = await self._check_provocations(user.user_id)
        if has_provocation:
            score += patterns.get('provocation_score', 30)
            flags.append('provocation')
        
        # Ограничиваем score до 100
        score = min(score, 100)
        
        return score, flags
    
    async def _check_office_hours_activity(self, user_id: int) -> bool:
        """
        Проверка: активность только в рабочие часы (9-18, пн-пт)
        """
        stmt = (
            select(func.count())
            .select_from(Message)
            .where(Message.user_id == user_id)
        )
        result = await self.session.execute(stmt)
        total = result.scalar() or 0
        
        if total == 0:
            return False
        
        # Считаем сообщения в рабочие часы
        # Примечание: для точной проверки нужно хранить время каждого сообщения
        # и анализировать распределение
        
        # Упрощённая версия: если >80% сообщений в рабочие часы
        # Требуется дополнительная логика анализа временных меток
        
        return False  # Заглушка
    
    async def _check_provocations(self, user_id: int) -> bool:
        """
        Проверка на провокационные сообщения в пользу УК
        """
        keywords = self.patterns.get('keywords_provocation', [
            'управляющая компания права',
            'ук говорит что',
            'надо платить больше',
        ])
        
        # Ищем сообщения с ключевыми словами
        for keyword in keywords:
            stmt = (
                select(func.count())
                .select_from(Message)
                .where(Message.user_id == user_id)
                .where(Message.text.ilike(f'%{keyword}%'))
            )
            result = await self.session.execute(stmt)
            count = result.scalar() or 0
            if count > 0:
                return True
        
        return False
    
    def _is_generic_username(self, username: str) -> bool:
        """Проверка на стандартный никнейм"""
        if not username:
            return True
        
        import re
        patterns = [
            r'^user\d+$',
            r'^user_\w+$',
            r'^id\d+$',
        ]
        return any(re.match(p, username.lower()) for p in patterns)
    
    async def update_spy_score(self, user: User) -> bool:
        """
        Обновить рейтинг подозрительности пользователя
        Возвращает True, если score изменился значительно
        """
        old_score = user.spy_score
        new_score, flags = await self.analyze_user(user)
        
        user.spy_score = new_score
        user.spy_flags = json.dumps(flags)
        
        # Логгируем изменение
        if abs(new_score - old_score) >= 20:
            await self._log_spy_detection(user, new_score, flags)
            return True
        
        return False
    
    async def _log_spy_detection(self, user: User, score: int, flags: List[str]):
        """Логирование детекта"""
        spy_log = SpyLog(
            user_id=user.user_id,
            spy_score=score,
            flags=json.dumps(flags),
        )
        self.session.add(spy_log)
        await self.session.commit()
    
    async def get_suspicious_users(self, min_score: int = 30) -> List[User]:
        """Получить список подозрительных пользователей"""
        stmt = (
            select(User)
            .where(User.spy_score >= min_score)
            .order_by(User.spy_score.desc())
        )
        result = await self.session.execute(stmt)
        return list(result.scalars().all())
    
    async def get_spies(self) -> List[User]:
        """Получить пользователей со статусом «шпион» (score > 60)"""
        return await self.get_suspicious_users(min_score=61)
