"""
Сериализаторы для пользователей.
"""
import re
from urllib.parse import unquote
from rest_framework import serializers
from django.contrib.auth.password_validation import validate_password
from django.contrib.auth import authenticate
from .models import User, Client, Parent, Group


def _decode_if_url_encoded(value: str) -> str:
    """Если строка в формате URL-encoded (%XX), декодирует в UTF-8."""
    if not value or not isinstance(value, str):
        return value
    if re.search(r'%[0-9A-Fa-f]{2}', value):
        try:
            return unquote(value, encoding='utf-8')
        except Exception:
            pass
    return value


class UserSerializer(serializers.ModelSerializer):
    """Базовый сериализатор пользователя."""
    
    avatar_url = serializers.SerializerMethodField()
    invitation_link = serializers.SerializerMethodField()
    login_link = serializers.SerializerMethodField()
    
    class Meta:
        model = User
        fields = [
            'id', 'email', 'first_name', 'last_name', 'role',
            'phone', 'avatar', 'avatar_url', 'birth_date', 'bio',
            'telegram_id', 'telegram_username',
            'timezone', 'language',
            'country', 'city',
            'email_verified', 'is_active',
            'universal_code',  # 8-символьный код (цифры + латинские буквы) для добавления ментором
            'onboarding_tours_seen',
            'invitation_link_token', 'invitation_link',
            'login_token', 'login_link',
            'notifications_enabled', 'email_notifications', 'telegram_notifications',
            'created_at', 'last_activity'
        ]
        read_only_fields = ['id', 'email_verified', 'universal_code', 'invitation_link_token', 'login_token', 'created_at', 'last_activity']
    
    def get_avatar_url(self, obj):
        """Получить полный URL аватара."""
        if obj.avatar:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.avatar.url)
            return obj.avatar.url
        return None

    def get_invitation_link(self, obj):
        """Получить полную ссылку-приглашение (только для менторов)."""
        if obj.role == 'mentor' and obj.invitation_link_token:
            from django.conf import settings
            frontend_url = getattr(settings, 'FRONTEND_URL', '').rstrip('/')
            return f"{frontend_url}/invite/{obj.invitation_link_token}"
        return None

    def get_login_link(self, obj):
        """Получить персональную ссылку для входа (для учеников)."""
        if obj.login_token:
            from django.conf import settings
            frontend_url = getattr(settings, 'FRONTEND_URL', '').rstrip('/')
            return f"{frontend_url}/login/token/{obj.login_token}"
        return None

    def to_representation(self, instance):
        """Декодируем first_name и last_name, если они пришли в БД в формате URL-encoded."""
        data = super().to_representation(instance)
        if 'first_name' in data and data['first_name']:
            data['first_name'] = _decode_if_url_encoded(data['first_name'])
        if 'last_name' in data and data['last_name']:
            data['last_name'] = _decode_if_url_encoded(data['last_name'])
        return data


class UserDetailSerializer(UserSerializer):
    """Детальный сериализатор пользователя с дополнительной информацией."""
    
    full_name = serializers.CharField(source='get_full_name', read_only=True)
    short_name = serializers.CharField(source='get_short_name', read_only=True)
    is_mentor = serializers.BooleanField(read_only=True)
    is_client = serializers.BooleanField(read_only=True)
    is_parent = serializers.BooleanField(read_only=True)
    
    class Meta(UserSerializer.Meta):
        fields = UserSerializer.Meta.fields + [
            'full_name', 'short_name', 'is_mentor', 'is_client', 'is_parent'
        ]


class RegisterSerializer(serializers.ModelSerializer):
    """Сериализатор для регистрации пользователя."""
    
    password = serializers.CharField(
        write_only=True,
        required=True,
        validators=[validate_password],
        style={'input_type': 'password'}
    )
    password_confirm = serializers.CharField(
        write_only=True,
        required=True,
        style={'input_type': 'password'}
    )
    
    class Meta:
        model = User
        fields = [
            'email', 'password', 'password_confirm',
            'first_name', 'last_name', 'role',
            'phone', 'birth_date', 'timezone', 'language',
            'country', 'city',
        ]
        extra_kwargs = {
            'first_name': {'required': True},
            'last_name': {'required': True},
            'city': {'required': True},
            'timezone': {'required': True},
        }
    
    def validate_email(self, value):
        """Нормализация email в нижний регистр."""
        return value.lower().strip() if value else value
    
    def validate(self, attrs):
        """Проверка совпадения паролей."""
        if attrs.get('password') != attrs.get('password_confirm'):
            raise serializers.ValidationError({
                'password_confirm': 'Пароли не совпадают'
            })
        return attrs
    
    def validate_role(self, value):
        """Проверка допустимых ролей при регистрации."""
        allowed_roles = ['client', 'mentor', 'parent']
        if value not in allowed_roles:
            raise serializers.ValidationError(
                f'Недопустимая роль. Доступные роли: {", ".join(allowed_roles)}'
            )
        return value
    
    def create(self, validated_data):
        """Создание пользователя."""
        validated_data.pop('password_confirm')
        password = validated_data.pop('password')
        
        user = User.objects.create_user(
            password=password,
            **validated_data
        )
        
        # Создаем профиль в зависимости от роли
        if user.role == 'client':
            Client.objects.create(user=user)
        elif user.role == 'parent':
            Parent.objects.create(user=user)
        
        return user


class TelegramAuthSerializer(serializers.Serializer):
    """Сериализатор для авторизации через Telegram."""
    
    id = serializers.IntegerField(required=True)
    first_name = serializers.CharField(required=True)
    last_name = serializers.CharField(required=False, allow_blank=True)
    username = serializers.CharField(required=False, allow_blank=True)
    photo_url = serializers.URLField(required=False, allow_blank=True)
    auth_date = serializers.IntegerField(required=True)
    hash = serializers.CharField(required=True)
    role = serializers.ChoiceField(
        choices=['mentor', 'client'],
        required=False,
        default='client',
        help_text='Роль пользователя при регистрации'
    )
    
    def validate(self, attrs):
        """Валидация данных Telegram."""
        from django.conf import settings
        from .telegram_auth import validate_telegram_data
        
        # Восстанавливаем hash для валидации
        telegram_data = {
            'id': attrs['id'],
            'first_name': attrs['first_name'],
            'last_name': attrs.get('last_name', ''),
            'username': attrs.get('username', ''),
            'photo_url': attrs.get('photo_url', ''),
            'auth_date': attrs['auth_date'],
            'hash': attrs['hash'],
        }
        
        # Удаляем пустые поля для валидации
        telegram_data = {k: v for k, v in telegram_data.items() if v}
        
        bot_token = settings.TELEGRAM_BOT_TOKEN
        if not bot_token:
            raise serializers.ValidationError("Telegram бот не настроен")
        
        if not validate_telegram_data(telegram_data.copy(), bot_token):
            raise serializers.ValidationError("Неверные данные Telegram")
        
        return attrs


class LoginSerializer(serializers.Serializer):
    """Сериализатор для входа пользователя."""
    
    email = serializers.EmailField(required=True)
    password = serializers.CharField(
        required=True,
        write_only=True,
        style={'input_type': 'password'}
    )
    
    def validate_email(self, value):
        """Нормализация email в нижний регистр."""
        return value.lower().strip() if value else value
    
    def validate(self, attrs):
        """Проверка учетных данных."""
        email = attrs.get('email')
        password = attrs.get('password')
        
        if email and password:
            # Проверяем существование пользователя
            try:
                user = User.objects.get(email=email)
            except User.DoesNotExist:
                raise serializers.ValidationError({
                    'email': 'Пользователь с таким email не найден'
                })
            
            # Проверяем пароль
            if not user.check_password(password):
                raise serializers.ValidationError({
                    'password': 'Неверный пароль'
                })
            
            # Проверяем активность пользователя
            if not user.is_active:
                raise serializers.ValidationError({
                    'email': 'Аккаунт неактивен'
                })
            
            # Проверяем блокировку
            if user.is_blocked:
                raise serializers.ValidationError({
                    'email': f'Аккаунт заблокирован. Причина: {user.blocked_reason}'
                })
            
            attrs['user'] = user
        else:
            raise serializers.ValidationError({
                'email': 'Email и пароль обязательны'
            })
        
        return attrs


class ChangePasswordSerializer(serializers.Serializer):
    """Сериализатор для смены пароля."""
    
    old_password = serializers.CharField(
        required=True,
        write_only=True,
        style={'input_type': 'password'}
    )
    new_password = serializers.CharField(
        required=True,
        write_only=True,
        validators=[validate_password],
        style={'input_type': 'password'}
    )
    new_password_confirm = serializers.CharField(
        required=True,
        write_only=True,
        style={'input_type': 'password'}
    )
    
    def validate(self, attrs):
        """Проверка совпадения новых паролей."""
        if attrs.get('new_password') != attrs.get('new_password_confirm'):
            raise serializers.ValidationError({
                'new_password_confirm': 'Пароли не совпадают'
            })
        return attrs
    
    def validate_old_password(self, value):
        """Проверка старого пароля."""
        user = self.context['request'].user
        if not user.check_password(value):
            raise serializers.ValidationError('Неверный старый пароль')
        return value


class PasswordResetRequestSerializer(serializers.Serializer):
    """Сериализатор для запроса восстановления пароля."""
    
    email = serializers.EmailField(required=True)
    
    def validate_email(self, value):
        """Нормализация email в нижний регистр и проверка существования."""
        # Нормализуем email в нижний регистр
        normalized_email = value.lower().strip() if value else value
        try:
            User.objects.get(email=normalized_email)
        except User.DoesNotExist:
            # Не раскрываем информацию о существовании email
            pass
        return normalized_email


class PasswordResetConfirmSerializer(serializers.Serializer):
    """Сериализатор для подтверждения восстановления пароля."""
    
    token = serializers.CharField(required=True)
    new_password = serializers.CharField(
        required=True,
        write_only=True,
        validators=[validate_password],
        style={'input_type': 'password'}
    )
    new_password_confirm = serializers.CharField(
        required=True,
        write_only=True,
        style={'input_type': 'password'}
    )
    
    def validate(self, attrs):
        """Проверка совпадения паролей."""
        if attrs.get('new_password') != attrs.get('new_password_confirm'):
            raise serializers.ValidationError({
                'new_password_confirm': 'Пароли не совпадают'
            })
        return attrs


class EmailVerificationSerializer(serializers.Serializer):
    """Сериализатор для подтверждения email."""
    
    token = serializers.CharField(required=True)


class ClientSerializer(serializers.ModelSerializer):
    """Сериализатор для клиента."""
    
    user = UserSerializer(read_only=True)
    mentors = UserSerializer(many=True, read_only=True)  # Добавляем менторов
    scheduled_lessons = serializers.SerializerMethodField()
    total_lessons = serializers.SerializerMethodField()
    completed_lessons = serializers.SerializerMethodField()
    
    class Meta:
        model = Client
        fields = [
            'id', 'user', 'mentors', 'grade', 'school', 'learning_goals',
            'total_lessons', 'completed_lessons', 'scheduled_lessons',
            'enrollment_date', 'created_at'
        ]
        read_only_fields = [
            'id', 'total_lessons', 'completed_lessons', 'scheduled_lessons',
            'enrollment_date', 'created_at'
        ]
    
    def get_scheduled_lessons(self, obj):
        """Количество запланированных занятий."""
        # Оптимизация: если queryset был заранее аннотирован, не делаем отдельные запросы в БД
        if hasattr(obj, 'scheduled_lessons_annotated'):
            return int(getattr(obj, 'scheduled_lessons_annotated') or 0)
        from apps.schedule.models import Lesson
        request = self.context.get('request')
        if request and request.user and request.user.role == 'mentor':
            # Считаем только занятия этого ментора
            return Lesson.objects.filter(
                client=obj,
                mentor=request.user,
                status='scheduled'
            ).count()
        # Если нет контекста, считаем все занятия
        return Lesson.objects.filter(
            client=obj,
            status='scheduled'
        ).count()
    
    def get_total_lessons(self, obj):
        """Общее количество занятий (все статусы кроме отмененных)."""
        # Оптимизация: если queryset был заранее аннотирован, не делаем отдельные запросы в БД
        if hasattr(obj, 'total_lessons_annotated'):
            return int(getattr(obj, 'total_lessons_annotated') or 0)
        from apps.schedule.models import Lesson
        request = self.context.get('request')
        if request and request.user and request.user.role == 'mentor':
            # Считаем только занятия этого ментора
            return Lesson.objects.filter(
                client=obj,
                mentor=request.user
            ).exclude(status='cancelled').count()
        # Если нет контекста, считаем все занятия
        return Lesson.objects.filter(
            client=obj
        ).exclude(status='cancelled').count()
    
    def get_completed_lessons(self, obj):
        """Количество завершенных занятий."""
        # Оптимизация: если queryset был заранее аннотирован, не делаем отдельные запросы в БД
        if hasattr(obj, 'completed_lessons_annotated'):
            return int(getattr(obj, 'completed_lessons_annotated') or 0)
        from apps.schedule.models import Lesson
        request = self.context.get('request')
        if request and request.user and request.user.role == 'mentor':
            # Считаем только занятия этого ментора
            return Lesson.objects.filter(
                client=obj,
                mentor=request.user,
                status='completed'
            ).count()
        # Если нет контекста, считаем все занятия
        return Lesson.objects.filter(
            client=obj,
            status='completed'
        ).count()


class ParentSerializer(serializers.ModelSerializer):
    """Сериализатор для родителя."""
    
    user = UserSerializer(read_only=True)
    children = ClientSerializer(many=True, read_only=True)
    
    class Meta:
        model = Parent
        fields = [
            'id', 'user', 'children', 'relation_type',
            'can_view_progress', 'can_view_schedule', 'can_receive_reports',
            'created_at'
        ]
        read_only_fields = ['id', 'created_at']


class GroupSerializer(serializers.ModelSerializer):
    """Сериализатор учебной группы."""

    mentor = UserSerializer(read_only=True)
    students = ClientSerializer(many=True, read_only=True)
    students_ids = serializers.ListField(
        child=serializers.IntegerField(),
        write_only=True,
        required=False,
        allow_empty=True,
    )
    students_count = serializers.SerializerMethodField()
    scheduled_lessons = serializers.SerializerMethodField()
    completed_lessons = serializers.SerializerMethodField()

    class Meta:
        model = Group
        fields = [
            'id',
            'mentor',
            'name',
            'description',
            'students',
            'students_ids',
            'students_count',
            'scheduled_lessons',
            'completed_lessons',
            'created_at',
            'updated_at',
        ]
        read_only_fields = ['id', 'mentor', 'students', 'students_count', 'scheduled_lessons', 'completed_lessons', 'created_at', 'updated_at']

    def get_students_count(self, obj):
        # Используем аннотацию, если она есть (для списка)
        if hasattr(obj, 'students_count_annotated'):
            return obj.students_count_annotated
        return obj.students.count()

    def _base_queryset(self, obj):
        """
        Базовый queryset занятий, относящихся к этой группе.
        Считаем ТОЛЬКО те уроки, которые явно привязаны к группе через поле Lesson.group,
        чтобы не путать общую историю ученика с его занятиями в составе конкретной группы.
        """
        from apps.schedule.models import Lesson

        return Lesson.objects.filter(
            mentor=obj.mentor,
            group=obj,
        ).exclude(status='cancelled')

    def get_scheduled_lessons(self, obj):
        """
        Количество запланированных занятий для текущей группы.
        Статусы: scheduled, in_progress.
        """
        # Используем аннотацию, если она есть (для списка)
        if hasattr(obj, 'scheduled_lessons_annotated'):
            return obj.scheduled_lessons_annotated
        qs = self._base_queryset(obj)
        return qs.filter(status__in=['scheduled', 'in_progress']).count()

    def get_completed_lessons(self, obj):
        """
        Количество проведённых (завершённых) занятий для текущей группы.
        Статус: completed.
        """
        # Используем аннотацию, если она есть (для списка)
        if hasattr(obj, 'completed_lessons_annotated'):
            return obj.completed_lessons_annotated
        qs = self._base_queryset(obj)
        return qs.filter(status='completed').count()

    def create(self, validated_data):
        students_ids = validated_data.pop('students_ids', [])
        request = self.context.get('request')
        mentor = request.user if request else None

        group = Group.objects.create(
            mentor=mentor,
            **validated_data,
        )

        if students_ids:
            students = Client.objects.filter(id__in=students_ids)
            group.students.set(students)

        return group

    def update(self, instance, validated_data):
        students_ids = validated_data.pop('students_ids', None)

        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()

        if students_ids is not None:
            students = Client.objects.filter(id__in=students_ids)
            instance.students.set(students)

        return instance
