from rest_framework import status
from datetime import datetime
import traceback
from django.conf import settings
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.views import APIView
from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiExample
from drf_spectacular.types import OpenApiTypes

from django.contrib.auth.models import User as DjangoUser

from .serializers import (
    UserResponseSerializer,
    LoginRequestSerializer,
    LoginResponseSerializer,
    LogoutResponseSerializer,
    RefreshTokenRequestSerializer,
    RefreshTokenResponseSerializer
)

from api.utils.cookies import AuthBaseViewSet


@extend_schema(tags=['Логин'])
class LoginViewSet(AuthBaseViewSet):
    """ViewSet для авторизации пользователей"""
    serializer_class = LoginRequestSerializer
    
    @extend_schema(
        summary="Авторизация пользователя",
        description="Эндпоинт для авторизации пользователя по логину и паролю",
        responses={
            200: OpenApiResponse(
                response=LoginResponseSerializer,
                description="Успешная авторизация",
                examples=[
                    OpenApiExample(
                        'Успешный ответ',
                        value={
                            "message": "Успешная авторизация",
                            "access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
                            "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...",
                            "user": {
                                "id": 1,
                                "email": "user@example.com",
                                "account_type": "engieneer",
                                "name": "Иван",
                                "surname": "Иванов",
                                "imageURL": "https://example.com/avatar.jpg",
                                "uuid": "abc123"
                            }
                        }
                    )
                ]
            ),
            400: OpenApiResponse(
                description="Неверные параметры запроса",
                response=OpenApiTypes.OBJECT,
                examples=[
                    OpenApiExample(
                        'Отсутствуют обязательные поля',
                        value={"error": "Логин и пароль обязательны"}
                    )
                ]
            ),
            403: OpenApiResponse(
                description="Неверный пароль",
                response=OpenApiTypes.OBJECT,
                examples=[
                    OpenApiExample(
                        'Неверный пароль',
                        value={"error": "Неверный пароль"}
                    )
                ]
            ),
            404: OpenApiResponse(
                description="Пользователь не найден",
                response=OpenApiTypes.OBJECT,
                examples=[
                    OpenApiExample(
                        'Пользователь не найден',
                        value={"error": "Пользователь не найден"}
                    )
                ]
            ),
            500: OpenApiResponse(
                description="Внутренняя ошибка сервера",
                response=OpenApiTypes.OBJECT,
                examples=[
                    OpenApiExample(
                        'Ошибка сервера',
                        value={"error": "Ошибка авторизации"}
                    )
                ]
            )
        }
    )
    @action(detail=False, methods=['post'], url_path="login")
    def login_client(self, request):
        try:
            login = request.data.get("login")
            password = request.data.get("password")
            
            if not login or not password:
                return Response(
                    {"error": "Логин и пароль обязательны"},
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            try:
                user = DjangoUser.objects.get(username=login)
            except DjangoUser.DoesNotExist:
                return Response(
                    {"error": "Пользователь не найден"},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            if not user.check_password(password):
                return Response(
                    {"error": "Неверный пароль"},
                    status=status.HTTP_403_FORBIDDEN
                )
            
            refresh = RefreshToken.for_user(user)
            
            user_data = UserResponseSerializer(user).data
            
            response = Response({
                "message": "Успешная авторизация",
                "access": str(refresh.access_token),
                "refresh": str(refresh),
                "user": user_data
            }, status=status.HTTP_200_OK)
            
            return self._set_auth_cookies(response, refresh)
                
        except Exception as e:
            return Response(
                {"error": "Ошибка авторизации"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

@extend_schema(tags=['Логин'])
class RefreshTokenView(APIView):
    """View для обновления JWT токенов"""
    serializer_class = RefreshTokenRequestSerializer

    @extend_schema(
        summary="Обновление токенов",
        description="Эндпоинт для обновления JWT токенов. Принимает refresh token и возвращает новую пару токенов.",
        request=RefreshTokenRequestSerializer,
        responses={
            200: OpenApiResponse(
                response=RefreshTokenResponseSerializer,
                description="Токены успешно обновлены",
                examples=[
                    OpenApiExample(
                        'Успешное обновление',
                        value={
                            "access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
                            "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...",
                            "expires_at": 1679831642.0
                        }
                    )
                ]
            ),
            400: OpenApiResponse(
                description="Ошибка обновления токена",
                response=OpenApiTypes.OBJECT,
                examples=[
                    OpenApiExample(
                        'Отсутствует refresh token',
                        value={"error": "Refresh token is required"}
                    ),
                    OpenApiExample(
                        'Невалидный refresh token',
                        value={"error": "Invalid refresh token: Token is invalid or expired"}
                    )
                ]
            )
        }
    )
    def post(self, request):
        try:
            refresh_token = request.data.get('refresh')
            
            if not refresh_token:
                return Response(
                    {'error': 'Требуется refresh token'}, 
                    status=status.HTTP_400_BAD_REQUEST
                )

            try:
                token = RefreshToken(refresh_token)

                # точное время истечения токена
                expires_at = datetime.now() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME']
                
                response_data = {
                    'access': str(token.access_token),
                    'refresh': str(token),
                    'expires_at': datetime.timestamp(expires_at)
                }
                
                return Response(response_data)
                
            except Exception as e:
                # логируем ошибки
               
                print(f"Token refresh error: {str(e)}")
                print(traceback.format_exc())
                
                return Response(
                    {'error': f'Невалидный refresh token: {str(e)}'}, 
                    status=status.HTTP_400_BAD_REQUEST
                )

        except Exception as e:
            return Response(
                {'error': f'Ошибка обновления токена: {str(e)}'}, 
                status=status.HTTP_400_BAD_REQUEST
            )

@extend_schema(tags=['Логаут'])
class LogoutView(APIView):
    """View для выхода из системы"""
    serializer_class = LogoutResponseSerializer
    
    @extend_schema(
        summary="Выход из системы",
        description="Эндпоинт для выхода из системы. Очищает JWT токены и сессионные куки.",
        responses={
            200: OpenApiResponse(
                response=LogoutResponseSerializer,
                description="Успешный выход из системы",
                examples=[
                    OpenApiExample(
                        'Успешный выход',
                        value={"message": "Успешный выход из системы"}
                    )
                ]
            )
        }
    )
    def post(self, request):
        """Выход из системы с очисткой всех токенов и куки"""
        response = Response(
            {'message': 'Успешный выход из системы'},
            status=status.HTTP_200_OK
        )
        
        response.delete_cookie('access_token')
        response.delete_cookie('refresh_token')
        response.delete_cookie('sessionid')
        
        return response