# Create your views here.
# billing/views.py
import os
from datetime import timedelta

import requests
from django.utils import timezone
from django.utils.timezone import localtime
from rest_framework import generics, status
from rest_framework.response import Response

from api.mixins import StaffEditorPermissionMixin
from api.tasks import add_new_devices_to_omada
from apibase.env import BASE_DIR, env
import logging

from .models import Device, Payment
from .serializers import PaymentSerializer, UpdatePaymentSerializer

env.read_env(os.path.join(BASE_DIR, ".env"))

PAYMENT_BASE_URL = env("PAYMENT_BASE_URL", default="")  # type: ignore

logger = logging.getLogger(__name__)


class InsufficientFundsError(Exception):
    pass


class ListCreatePaymentView(StaffEditorPermissionMixin, generics.ListCreateAPIView):
    serializer_class = PaymentSerializer
    queryset = Payment.objects.all().select_related("user")

    def get_queryset(self):
        queryset = super().get_queryset()
        if self.request.user.is_superuser:
            return queryset
        return queryset.filter(user=self.request.user)

    def create(self, request):
        data = request.data
        user = request.user
        amount = data.get("amount")
        number_of_months = data.get("number_of_months")
        device_ids = data.get("device_ids", [])
        print(amount, number_of_months, device_ids)

        for device_id in device_ids:
            device = Device.objects.filter(id=device_id, user=user).first()
            print("DEVICE", device)
            if not device:
                return Response(
                    {"message": f"Device with id {device_id} not found."},
                    status=status.HTTP_400_BAD_REQUEST,
                )
        if not amount or not number_of_months:
            return Response(
                {"message": "amount and number_of_months are required."},
                status=status.HTTP_400_BAD_REQUEST,
            )
        if not device_ids:
            return Response(
                {"message": "device_ids are required."},
                status=status.HTTP_400_BAD_REQUEST,
            )
        # Create payment
        payment = Payment.objects.create(
            amount=amount,
            number_of_months=number_of_months,
            paid=data.get("paid", False),
            user=user,
        )

        # Connect devices to payment
        devices = Device.objects.filter(id__in=device_ids, user=user)
        for device in devices:
            device.has_a_pending_payment = True
            device.save()
        payment.devices.set(devices)

        serializer = PaymentSerializer(payment)
        return Response(serializer.data, status=status.HTTP_201_CREATED)


class PaymentDetailAPIView(StaffEditorPermissionMixin, generics.RetrieveAPIView):
    queryset = Payment.objects.select_related("user").all()
    serializer_class = PaymentSerializer
    lookup_field = "pk"


class UpdatePaymentAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
    queryset = Payment.objects.select_related("user").all()
    serializer_class = UpdatePaymentSerializer
    lookup_field = "pk"

    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        number_of_months = instance.number_of_months
        device_expire_date = timezone.now() + timedelta(days=30 * number_of_months)
        devices = instance.devices.all()
        serializer = self.get_serializer(instance, data=request.data, partial=False)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        devices.update(
            is_active=True, expiry_date=device_expire_date, has_a_pending_payment=False
        )
        return Response(serializer.data)


class VerifyPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView):
    serializer_class = PaymentSerializer
    queryset = Payment.objects.all()
    lookup_field = "pk"

    def update(self, request, *args, **kwargs):
        # TODO: Fix check for success payment
        payment = self.get_object()
        data = request.data
        user = request.user
        print("logged in user", user)
        print("Payment user", payment.user)
        if payment.paid:
            return Response(
                {"message": "Payment has already been verified."},
                status=status.HTTP_400_BAD_REQUEST,
            )
        if payment.user != user and not user.is_superuser:
            return Response(
                {"message": "You are not authorized to verify this payment."},
                status=status.HTTP_403_FORBIDDEN,
            )
        method = data.get("method")
        if not method:
            return Response(
                {"message": "method is required. 'WALLET' or 'TRANSFER'"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        devices = payment.devices.all()
        payment_status = False
        if method == "WALLET":
            if user.wallet_balance < payment.amount:  # type: ignore
                return Response(
                    {"message": "Insufficient funds in wallet."},
                    status=status.HTTP_400_BAD_REQUEST,
                )
            else:
                payment_status = self.process_wallet_payment(
                    user,
                    payment,
                )
        if method == "TRANSFER":
            data = {
                "benefName": f"{user.first_name} {user.last_name}",  # type: ignore
                "accountNo": user.acc_no,  # type: ignore
                "absAmount": payment.amount,
                "time": localtime(timezone.now() + timedelta(minutes=5)).strftime(
                    "%Y-%m-%d %H:%M"
                ),
            }
            payment_status = self.verify_transfer_payment(data, payment)

        if payment_status:
            # Update devices
            expiry_date = timezone.now() + timedelta(days=30 * payment.number_of_months)
            devices.update(
                is_active=True,
                expiry_date=expiry_date,
                has_a_pending_payment=False,
                registered=True,
            )
            # Need to add to omada if its a new device and not an existing device
            device_list = []
            for device in devices:
                device_list.append(
                    {
                        "mac": device.mac,
                        "name": device.name,
                    }
                )
                if not device.registered:
                    # Add to omada
                    add_new_devices_to_omada.delay(new_devices=device_list)
                    device.registered = True
                    device.save()

            return Response(
                {"message": f"Payment verified successfully using [{method}]."}
            )
        else:
            return Response(
                {"message": f"Payment verification FAILED using [{method}]."}
            )

    def process_wallet_payment(self, user, payment):
        print("processing wallet payment...")
        print(user, payment.amount)

        payment.paid = True
        payment.paid_at = timezone.now()
        payment.method = "WALLET"
        payment.save()

        user.wallet_balance -= payment.amount
        user.save()
        return True

    def verify_transfer_payment(self, data, payment):
        if not PAYMENT_BASE_URL:
            raise ValueError(
                "PAYMENT_BASE_URL is not set. Please set it in your environment variables."
            )
        logger.info(data)
        response = requests.post(
            f"{PAYMENT_BASE_URL}/verify-payment",
            json=data,
            headers={"Content-Type": "application/json"},
        )
        response.raise_for_status()
        mib_resp = response.json()
        print(mib_resp)
        if not response.json().get("success"):
            return mib_resp["success"]
        else:
            payment.paid = True
            payment.paid_at = timezone.now()
            payment.method = "TRANSFER"
            payment.save()
            return True


class DeletePaymentView(StaffEditorPermissionMixin, generics.DestroyAPIView):
    queryset = Payment.objects.all()
    serializer_class = PaymentSerializer
    lookup_field = "pk"

    def delete(self, request, *args, **kwargs):
        instance = self.get_object()
        user = request.user
        if instance.user != user and not user.is_superuser:
            return Response(
                {"message": "You are not authorized to delete this payment."},
                status=status.HTTP_403_FORBIDDEN,
            )
        if instance.paid:
            return Response(
                {"message": "Paid payments cannot be deleted."},
                status=status.HTTP_400_BAD_REQUEST,
            )
        devices = instance.devices.all()
        devices.update(is_active=False, expiry_date=None, has_a_pending_payment=False)
        return super().delete(request, *args, **kwargs)