"""
Authentication views for the API.
Login, logout, register, and current user endpoints.
"""

from rest_framework import status
from rest_framework.throttling import ScopedRateThrottle
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.decorators import api_view, permission_classes
from django.contrib.auth import authenticate, login, logout
from django.views.decorators.csrf import ensure_csrf_cookie
from django.utils.decorators import method_decorator
from drf_spectacular.utils import extend_schema

from .serializers import UserSerializer


class LoginView(APIView):
    """Login with email and password, returns session cookie."""
    permission_classes = [AllowAny]
    throttle_classes = [ScopedRateThrottle]
    throttle_scope = "login"

    @extend_schema(
        request={
            'application/json': {
                'type': 'object',
                'properties': {
                    'email': {'type': 'string', 'format': 'email'},
                    'password': {'type': 'string'},
                },
                'required': ['email', 'password'],
            }
        },
        responses={200: UserSerializer}
    )
    def post(self, request):
        email = request.data.get('email')
        password = request.data.get('password')

        if not email or not password:
            return Response(
                {'error': 'Email and password are required'},
                status=status.HTTP_400_BAD_REQUEST
            )

        user = authenticate(request, username=email, password=password)

        if user is None:
            return Response(
                {'error': 'Invalid credentials'},
                status=status.HTTP_401_UNAUTHORIZED
            )

        login(request, user)
        return Response(UserSerializer(user, context={"request": request}).data)


class LogoutView(APIView):
    """Logout and clear session."""
    permission_classes = [AllowAny]

    @extend_schema(responses={200: {'type': 'object', 'properties': {'status': {'type': 'string'}}}})
    def post(self, request):
        logout(request)
        return Response({'status': 'logged out'})


class RegisterView(APIView):
    """Register a new user."""
    permission_classes = [AllowAny]
    throttle_classes = [ScopedRateThrottle]
    throttle_scope = "login"

    @extend_schema(
        request={
            'application/json': {
                'type': 'object',
                'properties': {
                    'email': {'type': 'string', 'format': 'email'},
                    'password': {'type': 'string'},
                    'password_confirm': {'type': 'string'},
                },
                'required': ['email', 'password', 'password_confirm'],
            }
        },
        responses={201: UserSerializer}
    )
    def post(self, request):
        from django.contrib.auth import get_user_model
        User = get_user_model()

        email = request.data.get('email')
        password = request.data.get('password')
        password_confirm = request.data.get('password_confirm')

        if not email or not password or not password_confirm:
            return Response(
                {'error': 'Email, password, and password confirmation are required'},
                status=status.HTTP_400_BAD_REQUEST
            )

        if password != password_confirm:
            return Response(
                {'error': 'Passwords do not match'},
                status=status.HTTP_400_BAD_REQUEST
            )

        if User.objects.filter(email=email).exists():
            return Response(
                {'error': 'A user with this email already exists'},
                status=status.HTTP_400_BAD_REQUEST
            )

        user = User.objects.create_user(email=email, password=password)
        login(request, user)
        return Response(
            UserSerializer(user, context={"request": request}).data,
            status=status.HTTP_201_CREATED,
        )


class MeView(APIView):
    """Current authenticated user. GET returns profile, PATCH updates it (incl. avatar upload)."""
    permission_classes = [IsAuthenticated]

    def get_parsers(self):
        from rest_framework.parsers import JSONParser, MultiPartParser, FormParser
        return [JSONParser(), MultiPartParser(), FormParser()]

    @extend_schema(responses={200: UserSerializer})
    def get(self, request):
        return Response(UserSerializer(request.user, context={"request": request}).data)

    @extend_schema(request=UserSerializer, responses={200: UserSerializer})
    def patch(self, request):
        serializer = UserSerializer(
            request.user, data=request.data, partial=True, context={"request": request}
        )
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)


# Function-based shim retained for URL backwards compat
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def me(request):
    """Get current authenticated user."""
    return Response(UserSerializer(request.user, context={"request": request}).data)


@api_view(['GET'])
@permission_classes([AllowAny])
def session_check(request):
    """Check if user has a valid session."""
    if request.user.is_authenticated:
        return Response({
            'authenticated': True,
            'user': UserSerializer(request.user, context={"request": request}).data
        })
    return Response({'authenticated': False})


class ChangePasswordView(APIView):
    """Authenticated user changes their own password. Clears must_change_password."""
    permission_classes = [IsAuthenticated]

    @extend_schema(
        request={
            'application/json': {
                'type': 'object',
                'properties': {
                    'current_password': {'type': 'string'},
                    'new_password': {'type': 'string'},
                },
                'required': ['current_password', 'new_password'],
            }
        },
        responses={200: UserSerializer},
    )
    def post(self, request):
        current = request.data.get('current_password')
        new = request.data.get('new_password')
        if not current or not new:
            return Response({'error': 'current_password and new_password required'},
                            status=status.HTTP_400_BAD_REQUEST)
        user = request.user
        if not user.check_password(current):
            return Response({'error': 'Current password incorrect'},
                            status=status.HTTP_400_BAD_REQUEST)
        if len(new) < 8:
            return Response({'error': 'New password must be at least 8 characters'},
                            status=status.HTTP_400_BAD_REQUEST)
        if new == current:
            return Response({'error': 'New password must differ from current'},
                            status=status.HTTP_400_BAD_REQUEST)
        user.set_password(new)
        user.must_change_password = False
        user.save(update_fields=['password', 'must_change_password'])
        # Re-auth session after password change
        from django.contrib.auth import update_session_auth_hash
        update_session_auth_hash(request, user)
        return Response(UserSerializer(user, context={"request": request}).data)


@method_decorator(ensure_csrf_cookie, name='dispatch')
class CSRFView(APIView):
    """Issue CSRF cookie + return token in body.

    Cookie covers same-site frontends; body token enables cross-origin
    frontends (different eTLD+1) where JS cannot read the cookie.
    """
    permission_classes = [AllowAny]

    @extend_schema(responses={200: None})
    def get(self, request):
        from django.middleware.csrf import get_token
        return Response({'csrfToken': get_token(request)})
