from rest_framework.generics import ListAPIView, ListCreateAPIView, UpdateAPIView, RetrieveUpdateAPIView, \
    GenericAPIView, RetrieveAPIView
from rest_framework_simplejwt.tokens import RefreshToken
from django.core import serializers as core_serializer
from django.contrib.auth import login, logout
from rest_framework.response import Response
from rest_framework.views import APIView
from seller import models as sellerModel
from rest_framework import permissions
from django.http import JsonResponse
from rest_framework import status
from . import models as userModel
from operator import attrgetter
from . import exceptions as ex
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from django.db.models import Q
from itertools import chain
from . import serializers
from . import permission
from . import sms
from customer.serializers import SignupWithJustMobileSerializer


class Register(GenericAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.RegisterSerializer

    @swagger_auto_schema(manual_parameters=[
        openapi.Parameter(
            'from',
            openapi.IN_QUERY,
            description="Optional search term",
            type=openapi.TYPE_STRING,
            required=False
        ),
    ])
    def post(self, request):
        from_value = self.request.query_params.get('from')
        mobile_number = request.data['mobile_number']
        verification_code = ''
        if 'verification_code' in request.data:
            verification_code = request.data['verification_code']
            response = sms.verify_code(mobile_number, verification_code)
        else:
            response = sms.send_otp(mobile_number)

        if response == 'failed':
            raise ex.SMSFailed
        elif response == 'sent':
            content = {'response': 'کد به شماره موبایل شما ارسال شد'}
            return Response(content, status=status.HTTP_200_OK)
        elif response == 'wrong code':
            raise ex.WrongCode
        elif response == 'expired':
            raise ex.ExpireCode
        elif response == 'ok':
            content = self._login(mobile_number, from_value)
            return Response(content, status=status.HTTP_200_OK)
        else:
            raise ex.ServerError

    def _login(self, mobile_number, from_value):
        user = userModel.User.objects.filter(mobile=mobile_number).first()
        if not user and from_value == "bot":
            serializer = SignupWithJustMobileSerializer(data={"mobile": mobile_number})
            serializer.is_valid(raise_exception=True)
            user = serializer.save()
        user.validated = True
        user.save()
        login(self.request, user)
        refresh = RefreshToken.for_user(self.request.user)
        content = {
            "id": self.request.user.id,
            "type": user.get_user_type(),
            "access": str(refresh.access_token),
            "refresh": str(refresh)
        }
        return content


class Login(GenericAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.LoginSerializer

    def post(self, request):
        try:
            user = userModel.User.objects.get(username=request.data["username"])
        except userModel.User.DoesNotExist:
            raise ex.WrongUserPass
        if user.check_password(request.data["password"]) and user.validated:
            login(self.request, user)
            refresh = RefreshToken.for_user(self.request.user)
            content = {
                "id": self.request.user.id,
                "type": user.get_user_type(),
                "access": str(refresh.access_token),
                "refresh": str(refresh)
            }
            return Response(content, status=status.HTTP_200_OK)
        else:
            raise ex.WrongUserPass


class CheckDuplication(GenericAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.DuplicationSerializer

    def post(self, request):
        serializer = serializers.DuplicationSerializer(data=self.request.data)
        if serializer.is_valid():
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class Logout(GenericAPIView):
    serializer_class = serializers.LogoutSerializer

    def post(self, request):
        refresh_token = self.request.data["refresh"]
        token = RefreshToken(refresh_token)
        token.blacklist()
        logout(request)
        return Response("Successful Logout", status=status.HTTP_200_OK)


class ProvinceCities(APIView):
    swagger_schema = None
    permission_classes = [permissions.AllowAny]

    def post(self, request, format=None):
        province = self.request.data['province']
        cities = {}
        if province:
            cities = userModel.City.objects.filter(province_id=province).order_by('name')
        data = core_serializer.serialize('json', cities)
        return JsonResponse(data=data, safe=False)


class ProvincesList(ListAPIView):
    permission_classes = [permissions.AllowAny]
    queryset = userModel.Province.objects.all()
    serializer_class = serializers.ProvincesListSerializer


class CitiesListByProvince(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CitiesListSerializer

    def get_queryset(self):
        return userModel.City.objects.filter(province_id=self.kwargs['province'])


class ListCreateAddress(ListCreateAPIView):
    serializer_class = serializers.AddressSerializer

    def get_queryset(self):
        if self.request.user.id == self.kwargs.get('user'):
            return userModel.Address.objects.filter(user_id=self.kwargs['user'])
        raise ex.ForbiddenException

    def perform_create(self, serializer):
        if self.request.user.id == self.kwargs.get('user'):
            serializer.save(user_id=self.request.user.id)


class RetrieveUpdateAddress(RetrieveUpdateAPIView):
    serializer_class = serializers.AddressSerializer
    queryset = userModel.Address.objects.all()
    permission_classes = [permission.IsRelatedUser]


class ChangePassword(UpdateAPIView):
    serializer_class = serializers.ChangePasswordSerializer
    queryset = userModel.User.objects.all()


class RetrieveMessages(RetrieveAPIView):
    serializer_class = serializers.MessageSerializer

    def get(self, request, *args, **kwargs):
        if self.request.user.id == self.kwargs.get('pk'):
            user = userModel.User.objects.get(id=self.kwargs.get('pk'))
            specific_related = user.message_set.all()
            general_related = ''
            try:
                sellerModel.Seller.objects.get(user_ptr=user.id)
                general_related = userModel.Message.objects.filter(Q(send_type='users') | Q(send_type='sellers'))
            except sellerModel.Seller.DoesNotExist:
                general_related = userModel.Message.objects.filter(Q(send_type='users') | Q(send_type='customers'))
            queryset = sorted(chain(specific_related, general_related), key=attrgetter('id'), reverse=True)
            return Response(serializers.MessageSerializer(queryset, many=True).data)
        raise ex.ForbiddenException
