# apps/auth/serializers.py

import random
from django.contrib.auth import authenticate
from django.core.cache import cache
from rest_framework import serializers
from rest_framework_simplejwt.tokens import RefreshToken

from .models import User, AuditLog

def _generate_otp() -> str:
    return str(random.randint(100000, 999999))


def _otp_cache_key(email: str) -> str:
    return f"otp:{email}"


class RegisterSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True, min_length=8)

    class Meta:
        model = User
        fields = ["email", "full_name", "password", "phone"]

    def create(self, validated_data):
        user = User.objects.create_user(
            email=validated_data["email"],
            password=validated_data["password"],
            full_name=validated_data["full_name"],
            phone=validated_data.get("phone", ""),
            is_active=False,  # inactive until OTP verified
        )
        otp = _generate_otp()
        cache.set(_otp_cache_key(user.email), otp, timeout=300)  # 5 min TTL

        # TODO: send OTP via email / SMS
        # send_otp_email(user.email, otp)
        print(f"[DEV] OTP for {user.email}: {otp}")  # remove in prod
        return user


class VerifyOTPSerializer(serializers.Serializer):
    email = serializers.EmailField()
    otp = serializers.CharField(max_length=6)

    def validate(self, data):
        cached = cache.get(_otp_cache_key(data["email"]))
        if not cached or cached != data["otp"]:
            raise serializers.ValidationError("Invalid or expired OTP.")
        return data

    def save(self):
        email = self.validated_data["email"]
        User.objects.filter(email=email).update(is_active=True)
        cache.delete(_otp_cache_key(email))
        return User.objects.get(email=email)


class ResendOTPSerializer(serializers.Serializer):
    email = serializers.EmailField()

    def validate_email(self, value):
        try:
            self._user = User.objects.get(email=value, is_active=False)
        except User.DoesNotExist:
            raise serializers.ValidationError(
                "No pending account found for this email."
            )
        return value

    def save(self):
        otp = _generate_otp()
        cache.set(_otp_cache_key(self._user.email), otp, timeout=300)
        print(f"[DEV] Resent OTP for {self._user.email}: {otp}")  # remove in prod
        return self._user


class LoginSerializer(serializers.Serializer):
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True)

    def validate(self, data):
        user = authenticate(email=data["email"], password=data["password"])
        if not user:
            raise serializers.ValidationError("Invalid credentials.")
        if not user.is_active:
            raise serializers.ValidationError("Account is not verified.")
        self._user = user
        return data

    def get_tokens(self, request=None) -> dict:
        refresh = RefreshToken.for_user(self._user)
        if request:
            ip = request.META.get("REMOTE_ADDR")
            User.objects.filter(pk=self._user.pk).update(last_login_ip=ip)
        return {
            "refresh": str(refresh),
            "access": str(refresh.access_token),
        }


class TokenRefreshSerializer(serializers.Serializer):
    """Thin wrapper — actual refresh is handled by SimpleJWT."""

    refresh = serializers.CharField()


class ForgotPasswordSerializer(serializers.Serializer):
    email = serializers.EmailField()

    def validate_email(self, value):
        try:
            self._user = User.objects.get(email=value, is_active=True)
        except User.DoesNotExist:
            raise serializers.ValidationError("No active account with this email.")
        return value

    def save(self):
        otp = _generate_otp()
        cache.set(f"pwd_reset:{self._user.email}", otp, timeout=300)
        print(f"[DEV] Password reset OTP for {self._user.email}: {otp}")
        return self._user


class ResetPasswordSerializer(serializers.Serializer):
    email = serializers.EmailField()
    otp = serializers.CharField(max_length=6)
    new_password = serializers.CharField(min_length=8, write_only=True)

    def validate(self, data):
        cached = cache.get(f"pwd_reset:{data['email']}")
        if not cached or cached != data["otp"]:
            raise serializers.ValidationError("Invalid or expired OTP.")
        return data

    def save(self):
        user = User.objects.get(email=self.validated_data["email"])
        user.set_password(self.validated_data["new_password"])
        user.save()
        cache.delete(f"pwd_reset:{user.email}")
        return user



class UserListSerializer(serializers.ModelSerializer):
    """Lightweight — used for GET list."""

    class Meta:
        model = User
        fields = ["id", "email", "full_name", "role", "is_active", "created_at"]


class UserDetailSerializer(serializers.ModelSerializer):
    """Full detail — used for GET by id."""

    class Meta:
        model = User
        fields = [
            "id",
            "email",
            "full_name",
            "phone",
            "avatar_url",
            "bio",
            "role",
            "is_active",
            "last_login_ip",
            "created_at",
            "updated_at",
        ]
        read_only_fields = ["id", "email", "created_at", "updated_at", "last_login_ip"]


class UserCreateSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True, min_length=8)

    class Meta:
        model = User
        fields = ["email", "full_name", "password", "phone", "role"]

    def create(self, validated_data):
        return User.objects.create_user(**validated_data)


class UserPatchSerializer(serializers.ModelSerializer):
    """PATCH — partial update. Restore action handled via 'action' field."""

    class RestoreAction(serializers.ChoiceField):
        pass

    action = serializers.ChoiceField(
        choices=["restore"],
        required=False,
        write_only=True,
        help_text="Pass 'restore' to un-delete (reactivate) a soft-deleted user.",
    )

    class Meta:
        model = User
        fields = [
            "full_name",
            "phone",
            "avatar_url",
            "bio",
            "role",
            "is_active",
            "action",
        ]

    def update(self, instance, validated_data):
        action = validated_data.pop("action", None)
        if action == "restore":
            validated_data["is_active"] = True
        for attr, val in validated_data.items():
            setattr(instance, attr, val)
        instance.save()
        return instance


class AuditLogSerializer(serializers.ModelSerializer):
    user_email = serializers.EmailField(source="user.email", read_only=True)

    class Meta:
        model = AuditLog
        fields = [
            "id",
            "user_email",
            "action",
            "model_name",
            "object_id",
            "description",
            "ip_address",
            "created_at",
        ]
