import re
from django.utils.text import slugify
from django.core.validators import MinValueValidator, MaxValueValidator
from rest_framework import serializers
from rest_framework.exceptions import NotFound
from django.contrib.auth import get_user_model
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from django.utils.translation import gettext_lazy as _
from django.utils.text import slugify

from .permissions import *


from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework.exceptions import PermissionDenied  


User = get_user_model()

class PublicUserSerializer(serializers.ModelSerializer):
    """Minimal read-only profile returned to non-owner authenticated users."""
    class Meta:
        model = User
        fields = ['id', 'username', 'first_name', 'last_name', 'avatar', 'banner', 'city', 'role', 'create_time']
        read_only_fields = ['id', 'username', 'first_name', 'last_name', 'avatar', 'banner', 'city', 'role', 'create_time']


class CustomUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = [
            "id",
            "username",
            "first_name",
            "last_name",
            "email",
            "role",
            "email_verified",
            "phone_number",
            "create_time",
            "city",
            "street",
            "postal_code",
            "gdpr",
            "is_active",
            "avatar",
            "banner",
        ]
        read_only_fields = ["id", "create_time", "gdpr", "username"]  # <-- removed "account_type"

        def update(self, instance, validated_data):
            user = self.context["request"].user
            staff_only_fields = ["role", "email_verified", "var_symbol", "is_active"]

            if user.role not in ["admin", "cityClerk"]:
                unauthorized = [f for f in staff_only_fields if f in validated_data]
                if unauthorized:
                    raise PermissionDenied(f"You are not allowed to modify: {', '.join(unauthorized)}")

            return super().update(instance, validated_data)

 


# Token obtaining Default Serializer
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    username_field = User.USERNAME_FIELD

    def validate(self, attrs):
        login = attrs.get("username")
        password = attrs.get("password")

        # Allow login by username or email
        user = User.objects.filter(email__iexact=login).first() or \
               User.objects.filter(username__iexact=login).first()

        if user is None or not user.check_password(password):
            raise serializers.ValidationError(_("No active account found with the given credentials"))

        if not user.is_active:
            raise serializers.ValidationError(_("Tento účet není aktivní. Ověřte prosím svůj e-mail."))

        # Call the parent validation to create token
        data = super().validate({
            self.username_field: user.username,
            "password": password
        })

        data["user_id"] = user.id
        data["username"] = user.username
        data["email"] = user.email
        return data


# user creating section start ------------------------------------------
class UserRegistrationSerializer(serializers.ModelSerializer):
    password = serializers.CharField(
        write_only=True,
        help_text="Heslo musí mít alespoň 8 znaků, obsahovat velká a malá písmena a číslici."
    )

    class Meta:
        model = User
        fields = [
            'username', 'first_name', 'last_name', 'email', 'phone_number', 'password',
            'city', 'street', 'postal_code', 'gdpr'
        ]
        extra_kwargs = {
            'username': {'required': False, 'allow_blank': True, 'help_text': 'Užívatelské jméno'},
            'first_name': {'required': False, 'allow_blank': True, 'help_text': 'Křestní jméno uživatele'},
            'last_name': {'required': False, 'allow_blank': True, 'help_text': 'Příjmení uživatele'},
            'email': {'required': True, 'help_text': 'Emailová adresa uživatele'},
            'phone_number': {'required': False, 'allow_null': True, 'allow_blank': True, 'help_text': 'Telefonní číslo uživatele'},
            'city': {'required': False, 'allow_blank': True, 'allow_null': True, 'help_text': 'Město uživatele'},
            'street': {'required': False, 'allow_blank': True, 'allow_null': True, 'help_text': 'Ulice uživatele'},
            'postal_code': {'required': False, 'allow_blank': True, 'allow_null': True, 'help_text': 'PSČ uživatele'},
            'gdpr': {'required': True, 'help_text': 'Souhlas se zpracováním osobních údajů'},
        }

    def validate_password(self, value):
        if len(value) < 8:
            raise serializers.ValidationError("Password must be at least 8 characters long.")
        if not re.search(r"[A-Z]", value):
            raise serializers.ValidationError("Password must contain at least one uppercase letter.")
        if not re.search(r"[a-z]", value):
            raise serializers.ValidationError("Password must contain at least one lowercase letter.")
        if not re.search(r"\d", value):
            raise serializers.ValidationError("Password must contain at least one digit.")
        return value

    def validate(self, data):
        email = data.get("email")
        phone = data.get("phone_number")
        gdpr = data.get("gdpr")
        if not gdpr:
            raise serializers.ValidationError({"gdpr": "You must agree to the GDPR to register."})

        if User.objects.filter(email=email).exists():
            raise serializers.ValidationError({"email": "Account with this email already exists."})

        if phone and User.objects.filter(phone_number=phone).exists():
            raise serializers.ValidationError({"phone_number": "Account with this phone number already exists."})

        return data
    
    def create(self, validated_data):
        password = validated_data.pop("password")
        user = User.objects.create(
            is_active=True, #uživatel je defaultně aktivní
            **validated_data
        )
        user.set_password(password)
        user.save()

        return user
    
class UserActivationSerializer(serializers.Serializer):
    user_id = serializers.IntegerField()
    var_symbol = serializers.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(9999999999)])

    def save(self, **kwargs):
        try:
            user = User.objects.get(pk=self.validated_data['user_id'])
        except User.DoesNotExist:
            raise NotFound("User with this ID does not exist.")
        user.var_symbol = self.validated_data['var_symbol']
        user.is_active = True
        user.save()
        return user

    def to_representation(self, instance):
        return {
            "id": instance.id,
            "email": instance.email,
            "var_symbol": instance.var_symbol,
            "is_active": instance.is_active,
        }
    
    class Meta:
        model = User
        fields = [
            'user_id', 'var_symbol'
        ]
        extra_kwargs = {
            'user_id': {'required': True, 'help_text': 'ID uživatele'},
            'var_symbol': {'required': True, 'help_text': 'Variablní symbol, zadán úředníkem'},
        }
# user creating section end --------------------------------------------


class PasswordResetRequestSerializer(serializers.Serializer):
    email = serializers.EmailField(
        help_text="E-mail registrovaného a aktivního uživatele, na který bude zaslán reset hesla."
    )

    def validate_email(self, value):
        if not User.objects.filter(email=value, is_active=True).exists():
            raise serializers.ValidationError("Účet s tímto emailem neexistuje nebo není aktivní.")
        return value
    
class PasswordResetConfirmSerializer(serializers.Serializer):
    password = serializers.CharField(
        write_only=True,
        help_text="Nové heslo musí mít alespoň 8 znaků, obsahovat velká a malá písmena a číslici."
    )

    def validate_password(self, value):
        import re
        if len(value) < 8:
            raise serializers.ValidationError("Heslo musí mít alespoň 8 znaků.")
        if not re.search(r"[A-Z]", value):
            raise serializers.ValidationError("Musí obsahovat velké písmeno.")
        if not re.search(r"[a-z]", value):
            raise serializers.ValidationError("Musí obsahovat malé písmeno.")
        if not re.search(r"\d", value):
            raise serializers.ValidationError("Musí obsahovat číslici.")
        return value


class ChangeEmailSerializer(serializers.Serializer):
    current_password = serializers.CharField(write_only=True)
    new_email = serializers.EmailField()
    turnstile_token = serializers.CharField(write_only=True, required=False, allow_blank=True)

    def validate_new_email(self, value):
        value = value.lower()
        if User.objects.filter(email__iexact=value).exists():
            raise serializers.ValidationError("Tento e-mail je již používán.")
        return value


class ChangeUsernameSerializer(serializers.Serializer):
    new_username = serializers.CharField(min_length=3, max_length=150)
    turnstile_token = serializers.CharField(write_only=True, required=False, allow_blank=True)

    def validate_new_username(self, value):
        import re
        if not re.match(r'^[\w.@+-]+$', value):
            raise serializers.ValidationError("Povolena jsou písmena, číslice a znaky @/./+/-/_.")
        if User.objects.filter(username__iexact=value).exists():
            raise serializers.ValidationError("Toto uživatelské jméno je již obsazeno.")
        return value


class ChangePasswordSerializer(serializers.Serializer):
    current_password = serializers.CharField(write_only=True)
    new_password = serializers.CharField(write_only=True)

    def validate_new_password(self, value):
        import re
        if len(value) < 8:
            raise serializers.ValidationError("Heslo musí mít alespoň 8 znaků.")
        if not re.search(r"[A-Z]", value):
            raise serializers.ValidationError("Musí obsahovat velké písmeno.")
        if not re.search(r"[a-z]", value):
            raise serializers.ValidationError("Musí obsahovat malé písmeno.")
        if not re.search(r"\d", value):
            raise serializers.ValidationError("Musí obsahovat číslici.")
        return value