from django.db import transaction
from django.http.response import JsonResponse
from rest_framework import status
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny
from rest_framework.response import Response

from apps.authentication.models import Organization
from apps.authentication.services.service import get_users_of_organization
from apps.pos_device import models as pos_models
from apps.pos_device.mixins.pos_device_mixin import POSDeviceMixin
from apps.pos_device.pos.api.v1.serializers.device import DeviceSerializer
from common.generics import get_client_ip


def test_web_server(request):
    """ testing from pos device to check server status """
    return JsonResponse({"message": "OK"}, status=status.HTTP_200_OK)


class POSDeviceViewSet(viewsets.ModelViewSet, POSDeviceMixin):
    device_queryset = pos_models.Device.objects.all()
    session_queryset = pos_models.Sessions.objects.all()
    serializer_class = DeviceSerializer
    HEADERS = [
        'device-mac', 'device-serial', 'device-name',
        'device-sdk', 'device-version',
        'device-lng', 'device-lot', 'device-provider',  # noqa
        'device-vname',  # noqa
    ]
    permission_classes = [AllowAny]

    @action(
        methods=['post'],
        detail=False,
        url_path='login',
        url_name='login',
        name='login'
    )
    @transaction.atomic
    def login(self, request):
        """ login of pos device """
        """
            # get device owner (organization)
            organization = self.get_device_organization()
        """
        # convert headers to dictionary
        headers_data = {key: request.headers.get(key) for key in self.HEADERS}

        serial = headers_data['device-serial']
        mac = headers_data['device-mac']
        psp_name = headers_data['device-provider']

        # MNPC Company object information  # noqa
        main_company = Organization.objects.get(national_unique_id='1111111111')

        # provider organization
        organization = pos_models.Organization.objects.get(en_name=psp_name)

        # device version
        device_version = pos_models.DeviceVersion.objects.filter(
            organization=organization,
            enable=True
        ).order_by('-code')

        device = self.device_queryset.filter(serial=serial).first()

        if not device and 'device_identity' in request.data.keys() and request.data['device_identity'] != "":
            device = self.device_queryset.filter(device_identity=request.data['device_identity']).first()

        if device:
            if not device.is_activated and device.pre_registered and device.assigned_state:
                # activate device
                device.is_activated = True
                device.save()

            if device.is_activated and device.assigned_state:
                # when device is logged in, its has an organization owner client, if not it will show error
                device_owner_org = self.get_device_organization()

                session = self.session_queryset.filter(serial=serial).first()
                if not session:
                    pos_models.Sessions.objects.create(
                        device=device,
                        name=headers_data['device-name'],
                        version=headers_data['device-version'],
                        mac=headers_data['device-mac'],
                        ip=get_client_ip(request),
                        sdk=headers_data['device-sdk'],
                        serial=headers_data['device-serial'],
                        latitude=headers_data['device-lot'],
                        longitude=headers_data['device-lng'],
                    )
                else:
                    session.name = headers_data['device-name']
                    session.version = headers_data['device-version']
                    session.mac = headers_data['device-mac']
                    session.ip = get_client_ip(request)
                    session.sdk = headers_data['device-sdk']
                    session.latitude = headers_data['device-lot']
                    session.longitude = headers_data['device-lng']
                    session.save()

                org_data = {
                    'id': device_owner_org.id,
                    'name': device_owner_org.name,
                    'en_name': device_owner_org.en_name,
                    'phone': device_owner_org.phone,
                    'type': device_owner_org.type.name,
                    'shaba': device_owner_org.bank_information.all().first().sheba,  # noqa
                    'province': device_owner_org.province.name,
                }

                return Response({
                    "message": "خوش آمدید",  # noqa
                    "device_identity": device.device_identity,
                    "serial": device.serial,
                    "password": device.password,
                    "provider": organization.name,
                    "provider_tell": organization.phone,
                    "device_owner": org_data,
                    "device_owner_users": get_users_of_organization(device_owner_org),
                    "main_company": {
                        "name": main_company.name,
                        "phone": main_company.phone,
                        "shaba": main_company.bank_information.all().first().sheba,  # noqa
                        "amount": 400
                    },
                    'latest_version_code': device_version.first().code if device_version.exists() else None,
                    'latest_version_link': device_version.first().url if device_version.exists() else None,
                    'latest_version_checksum': device_version.first().checksum if device_version.exists() else None,
                }, status=status.HTTP_200_OK)

            return Response({
                "message": "دستگاه در سیستم ثبت در انتظار فعال سازی توسط پذیرنده می باشد",  # noqa
                "device_identity": device.device_identity,
                "password": "****",
                "serial": device.serial,
                "provider": organization.name,
                "provider_tell": organization.phone,
                "main_company": {
                    "name": main_company.name,
                    "phone": main_company.phone,
                    "shaba": main_company.bank_information.all().first().sheba,  # noqa
                    "amount": 400
                }
            }, status=status.HTTP_401_UNAUTHORIZED)

        else:
            pre_device = pos_models.Device.objects.create(
                serial=serial,
                mac=mac,
                organization=organization,
                pre_registered=True,
                is_activated=False
            )

            return Response({
                "message": "دستگاه در سیستم ثبت در انتظار فعال سازی توسط پذیرنده می باشد",  # noqa
                "device_identity": pre_device.device_identity,
                "password": "****",
                "provider": organization.name,
                "provider_tell": organization.phone,
                "main_company": {
                    "name": main_company.name,
                    "phone": main_company.phone,
                    "shaba": main_company.bank_information.all().first().sheba,  # noqa
                    "amount": 400
                }
            }, status=status.HTTP_412_PRECONDITION_FAILED)

    @action(
        methods=['post'],
        detail=False,
        url_path='merge_devices',
        url_name='merge_devices',
        name='merge_devices'
    )
    @transaction.atomic
    def merge_devices(self, request):
        """ merge pre register device & device has registered by psp user """

        pre_device = self.device_queryset.get(device_identity=request.data['pre_device_identity'])
        real_device = self.device_queryset.get(device_identity=request.data['real_device_identity'])

        real_device.device_identity = pre_device.device_identity
        real_device.is_activated = True
        real_device.save()

        pre_device.delete()

        return Response({
            "message": "device merged successfully",
            "device_identity": real_device.device_identity,
            "serial": real_device.serial
        })
