"""
Authentication domain serializers for ThrillWiki API v1.

This module contains all serializers related to user authentication,
registration, password management, and social authentication.
"""

from django.contrib.auth import authenticate, get_user_model
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError as DjangoValidationError
from drf_spectacular.utils import (
    OpenApiExample,
    extend_schema_serializer,
)
from rest_framework import serializers

UserModel = get_user_model()


# === USER SERIALIZERS ===


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "User Output Example",
            summary="Example user response",
            description="A typical user object in API responses",
            value={
                "id": 1,
                "username": "thrillseeker",
                "email": "user@example.com",
                "first_name": "John",
                "last_name": "Doe",
                "is_active": True,
                "date_joined": "2024-01-01T00:00:00Z",
            },
        )
    ]
)
class UserOutputSerializer(serializers.ModelSerializer):
    """Output serializer for user data."""

    class Meta:
        model = UserModel
        fields = [
            "id",
            "username",
            "email",
            "first_name",
            "last_name",
            "is_active",
            "date_joined",
        ]
        read_only_fields = ["id", "date_joined"]


# === LOGIN SERIALIZERS ===


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Login Input Example",
            summary="Example login request",
            description="Login with username or email and password",
            value={
                "username": "thrillseeker",
                "password": "securepassword123",
            },
        )
    ]
)
class LoginInputSerializer(serializers.Serializer):
    """Input serializer for user login."""

    username = serializers.CharField(
        max_length=150,
        help_text="Username or email address",
    )
    password = serializers.CharField(
        write_only=True,
        style={"input_type": "password"},
        help_text="User password",
    )

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

        if username and password:
            # Try to authenticate with the provided credentials
            user = authenticate(
                request=self.context.get("request"),
                username=username,
                password=password,
            )

            if not user:  # noqa: SIM102
                # Try email-based authentication if username failed
                if "@" in username:
                    try:
                        user_obj = UserModel.objects.get(email=username)
                        user = authenticate(
                            request=self.context.get("request"),
                            username=user_obj.username,  # type: ignore[attr-defined]
                            password=password,
                        )
                    except UserModel.DoesNotExist:
                        pass

            if not user:
                raise serializers.ValidationError("Invalid credentials")

            if not user.is_active:
                raise serializers.ValidationError("Account is disabled")

            attrs["user"] = user
        else:
            raise serializers.ValidationError("Must include username and password")

        return attrs


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Login Output Example",
            summary="Example login response",
            description="Successful login response with token and user data",
            value={
                "token": "abc123def456ghi789",
                "user": {
                    "id": 1,
                    "username": "thrillseeker",
                    "email": "user@example.com",
                    "first_name": "John",
                    "last_name": "Doe",
                },
                "detail": "Login successful",
            },
        )
    ]
)
class LoginOutputSerializer(serializers.Serializer):
    """Output serializer for login response."""

    token = serializers.CharField(help_text="Authentication token")
    user = UserOutputSerializer(help_text="User information")
    message = serializers.CharField(help_text="Success message")


# === SIGNUP SERIALIZERS ===


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Signup Input Example",
            summary="Example registration request",
            description="Register a new user account",
            value={
                "username": "newuser",
                "email": "newuser@example.com",
                "password": "securepassword123",
                "password_confirm": "securepassword123",
                "first_name": "Jane",
                "last_name": "Smith",
            },
        )
    ]
)
class SignupInputSerializer(serializers.ModelSerializer):
    """Input serializer for user registration."""

    password = serializers.CharField(
        write_only=True,
        style={"input_type": "password"},
        help_text="User password",
    )
    password_confirm = serializers.CharField(
        write_only=True,
        style={"input_type": "password"},
        help_text="Password confirmation",
    )

    class Meta:
        model = UserModel
        fields = [
            "username",
            "email",
            "password",
            "password_confirm",
            "first_name",
            "last_name",
        ]

    def validate_email(self, value):
        """Validate email uniqueness."""
        if UserModel.objects.filter(email=value).exists():
            raise serializers.ValidationError("Email already registered")
        return value

    def validate_username(self, value):
        """Validate username uniqueness."""
        if UserModel.objects.filter(username=value).exists():
            raise serializers.ValidationError("Username already taken")
        return value

    def validate_password(self, value):
        """Validate password strength."""
        try:
            validate_password(value)
        except DjangoValidationError as e:
            raise serializers.ValidationError(list(e.messages)) from None
        return value

    def validate(self, attrs):
        """Cross-field validation."""
        password = attrs.get("password")
        password_confirm = attrs.get("password_confirm")

        if password != password_confirm:
            raise serializers.ValidationError("Passwords do not match")

        return attrs

    def create(self, validated_data):
        """Create new user."""
        validated_data.pop("password_confirm")
        password = validated_data.pop("password")

        user = UserModel.objects.create_user(  # type: ignore[attr-defined]
            password=password,
            **validated_data,
        )
        return user


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Signup Output Example",
            summary="Example registration response",
            description="Successful registration response with token and user data",
            value={
                "token": "abc123def456ghi789",
                "user": {
                    "id": 2,
                    "username": "newuser",
                    "email": "newuser@example.com",
                    "first_name": "Jane",
                    "last_name": "Smith",
                },
                "detail": "Registration successful",
            },
        )
    ]
)
class SignupOutputSerializer(serializers.Serializer):
    """Output serializer for registration response."""

    token = serializers.CharField(help_text="Authentication token")
    user = UserOutputSerializer(help_text="User information")
    message = serializers.CharField(help_text="Success message")


# === LOGOUT SERIALIZERS ===


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Logout Output Example",
            summary="Example logout response",
            description="Successful logout response",
            value={
                "detail": "Logout successful",
            },
        )
    ]
)
class LogoutOutputSerializer(serializers.Serializer):
    """Output serializer for logout response."""

    message = serializers.CharField(help_text="Success message")


# === PASSWORD RESET SERIALIZERS ===


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Password Reset Input Example",
            summary="Example password reset request",
            description="Request password reset email",
            value={
                "email": "user@example.com",
            },
        )
    ]
)
class PasswordResetInputSerializer(serializers.Serializer):
    """Input serializer for password reset request."""

    email = serializers.EmailField(help_text="Email address for password reset")

    def validate_email(self, value):
        """Validate email exists."""
        if not UserModel.objects.filter(email=value).exists():
            # Don't reveal if email exists for security
            pass
        return value

    def save(self, **kwargs):  # type: ignore[override]
        """Send password reset email."""
        email = self.validated_data["email"]  # type: ignore[index]
        try:
            # Check if email exists (but don't reveal the result for security)
            UserModel.objects.get(email=email)
            # Here you would typically send a password reset email
            pass
        except UserModel.DoesNotExist:
            # Don't reveal if email exists for security
            pass


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Password Reset Output Example",
            summary="Example password reset response",
            description="Password reset email sent response",
            value={
                "detail": "Password reset email sent",
            },
        )
    ]
)
class PasswordResetOutputSerializer(serializers.Serializer):
    """Output serializer for password reset response."""

    detail = serializers.CharField(help_text="Success message")


# === PASSWORD CHANGE SERIALIZERS ===


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Password Change Input Example",
            summary="Example password change request",
            description="Change current user's password",
            value={
                "old_password": "oldpassword123",
                "new_password": "newpassword456",
                "new_password_confirm": "newpassword456",
            },
        )
    ]
)
class PasswordChangeInputSerializer(serializers.Serializer):
    """Input serializer for password change."""

    old_password = serializers.CharField(
        write_only=True,
        style={"input_type": "password"},
        help_text="Current password",
    )
    new_password = serializers.CharField(
        write_only=True,
        style={"input_type": "password"},
        help_text="New password",
    )
    new_password_confirm = serializers.CharField(
        write_only=True,
        style={"input_type": "password"},
        help_text="New password confirmation",
    )

    def validate_old_password(self, value):
        """Validate current password."""
        user = self.context["request"].user
        if not user.check_password(value):
            raise serializers.ValidationError("Current password is incorrect")
        return value

    def validate_new_password(self, value):
        """Validate new password strength."""
        try:
            validate_password(value, user=self.context["request"].user)
        except DjangoValidationError as e:
            raise serializers.ValidationError(list(e.messages)) from None
        return value

    def validate(self, attrs):
        """Cross-field validation."""
        new_password = attrs.get("new_password")
        new_password_confirm = attrs.get("new_password_confirm")

        if new_password != new_password_confirm:
            raise serializers.ValidationError("New passwords do not match")

        return attrs

    def save(self, **kwargs):  # type: ignore[override]
        """Change user password."""
        user = self.context["request"].user
        user.set_password(self.validated_data["new_password"])  # type: ignore[index]
        user.save()
        return user


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Password Change Output Example",
            summary="Example password change response",
            description="Password changed successfully response",
            value={
                "detail": "Password changed successfully",
            },
        )
    ]
)
class PasswordChangeOutputSerializer(serializers.Serializer):
    """Output serializer for password change response."""

    detail = serializers.CharField(help_text="Success message")


# === SOCIAL PROVIDER SERIALIZERS ===


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Social Provider Example",
            summary="Example social provider",
            description="Available social authentication provider",
            value={
                "id": "google",
                "name": "Google",
                "authUrl": "https://example.com/accounts/google/login/",
            },
        )
    ]
)
class SocialProviderOutputSerializer(serializers.Serializer):
    """Output serializer for social authentication providers."""

    id = serializers.CharField(help_text="Provider ID")
    name = serializers.CharField(help_text="Provider display name")
    authUrl = serializers.URLField(help_text="Authentication URL")


# === AUTH STATUS SERIALIZERS ===


@extend_schema_serializer(
    examples=[
        OpenApiExample(
            "Auth Status Authenticated Example",
            summary="Example authenticated status",
            description="Response when user is authenticated",
            value={
                "authenticated": True,
                "user": {
                    "id": 1,
                    "username": "thrillseeker",
                    "email": "user@example.com",
                    "first_name": "John",
                    "last_name": "Doe",
                },
            },
        ),
        OpenApiExample(
            "Auth Status Unauthenticated Example",
            summary="Example unauthenticated status",
            description="Response when user is not authenticated",
            value={
                "authenticated": False,
                "user": None,
            },
        ),
    ]
)
class AuthStatusOutputSerializer(serializers.Serializer):
    """Output serializer for authentication status."""

    authenticated = serializers.BooleanField(help_text="Whether user is authenticated")
    user = UserOutputSerializer(allow_null=True, help_text="User information if authenticated")
