from django.contrib.auth import get_user_model, login
from django.conf import settings
from rest_framework import generics, permissions, viewsets, status
from rest_framework.response import Response
from rest_framework.views import APIView
from knox.models import AuthToken
from account.models import User
from rest_framework.filters import SearchFilter
from django_filters.rest_framework import DjangoFilterBackend
from account.serializer import AdminUserSerializer, UserSerializer, LoginSerializer, UserProfileSerializer, ResendOTPSerializer
from account.permissions import HasTabPermission
from account.audit import audit_event
from shop_management.views.data.base import DataRootViewSet
from .utils import send_otp_email,generate_otp  # Import OTP utilities
from account.view.change_password import ChangePasswordMixin
from django.contrib.auth import login
User = get_user_model()
# Register new users and send OTP to their email if they are a seller
from django.utils import timezone
from datetime import timedelta
from django.db.models import Q
from django.db.models.deletion import ProtectedError
from shop_management.models.data.shop import Shop
from shop_management.serializers.data.shop import ShopSerializer
from shop_management.models.data.account_transaction import AccountTransaction
from shop_management.models.data.account_transfer import AccountTransfer
from shop_management.models.data.advance import Advance
from shop_management.models.data.customer import Customer
from shop_management.models.data.customer_balance_payment import CustomerBalancePayment
from shop_management.models.data.employee import Employee
from shop_management.models.data.expense import Expense, ExpenseCategory
from shop_management.models.data.payroll import Payroll
from shop_management.models.data.product import Category, Product
from shop_management.models.data.purchase import Purchase, PurchaseItem
from shop_management.models.data.purchase_payment import PurchasePayment
from shop_management.models.data.purchase_return import PurchaseReturn, PurchaseReturnItem
from shop_management.models.data.sale import Sale, SaleItem
from shop_management.models.data.sale_payment import SalePayment
from shop_management.models.data.sale_return import SaleReturn, SaleReturnItem
from shop_management.models.data.shop_account import Account
from shop_management.models.data.stock import Stock
from shop_management.models.data.supplier import Supplier
from shop_management.models.data.utils import Currency, ExchangeRate, Unit


# Register new users and send OTP to their email if they are a seller
class RegisterAPI(generics.GenericAPIView):
    serializer_class = UserSerializer

    def post(self, request, *args, **kwargs):
        # Retrieve email from the request if provided.
        email = request.data.get("email")
        if email:
            try:
                existing_user = User.objects.get(email=email)
                # If the user exists and is a seller, ask to verify email.
                if existing_user.is_seller:
                    return Response(
                        {"message": "You already have an account, please verify your email."},
                        status=400
                    )
            except User.DoesNotExist:
                pass

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        # Create the user instance from the validated data.
        user = serializer.save()
        
        # If an email is provided and the user is a seller, generate OTP.
        if email and user.is_seller:
            otp = generate_otp()
            user.otp_secret = otp
            user.otp_expiry = timezone.now() + timedelta(minutes=30)
            user.save()
            send_otp_email(user, otp)
            message = "Registration successful. Please verify your email OTP."
        else:
            message = "Registration successful."

        return Response({
            "user": UserSerializer(user, context=self.get_serializer_context()).data,
            "message": message
        })



# Verify OTP sent to the user's email
class VerifyEmailOTPAPI(generics.GenericAPIView):
    permission_classes = [permissions.AllowAny]

    def post(self, request, *args, **kwargs):
        email = request.data.get("email")
        otp = request.data.get("otp")

        try:
            user = User.objects.get(email=email)
        except User.DoesNotExist:
            return Response({"error": "User not found."}, status=400)

        # Check OTP expiry before verifying
        if user.otp_expiry and timezone.now() > user.otp_expiry:
            return Response({"error": "OTP has expired. Please request a new one."}, status=400)

        # Verify OTP
        if user.otp_secret and user.otp_secret == otp:
            user.is_email_verified = True
            user.otp_secret = None  # Clear the OTP after successful verification
            user.otp_expiry = None  # Clear the OTP expiry
            user.save()

            token = AuthToken.objects.create(user)[1]
            login(request, user)

            return Response({
                "message": "Email verified successfully.",
                "user": UserSerializer(user, context=self.get_serializer_context()).data,
                "token": token
            })
        else:
            return Response({"error": "Invalid OTP."}, status=400)


# Resend OTP to the user's email
class ResendEmailOTPAPI(generics.GenericAPIView):
    serializer_class = ResendOTPSerializer  # Ensure this serializer exists and is appropriate
    permission_classes = [permissions.AllowAny]

    def post(self, request, *args, **kwargs):
        email = request.data.get("email")

        try:
            user = User.objects.get(email=email)
        except User.DoesNotExist:
            return Response({"error": "User not found."}, status=400)

        # Check if the user is a seller and hasn't verified their email yet.
        if user.is_seller and not user.is_email_verified:
            # Generate a new OTP, assign it to the user, and update expiry to 30 minutes from now.
            otp = generate_otp()
            user.otp_secret = otp
            user.otp_expiry = timezone.now() + timedelta(minutes=30)
            user.save()
            
            # Send OTP email with the new OTP.
            send_otp_email(user, otp)
            return Response({"message": "OTP has been resent to your email."})
        else:
            return Response({"error": "This user either doesn't require OTP or is already verified."}, status=400)



class LoginAPI(generics.GenericAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = LoginSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # Get the validated user
        user = serializer.validated_data["user"]

        # Check if the email is verified before allowing login for sellers
        if user.is_seller and not user.is_email_verified:
            return Response({"error": "Email is not verified. Please verify using OTP."}, status=400)

        # Login the user
        login(request, user)

        # Create a token using Knox
        token = AuthToken.objects.create(user)[1]
        audit_event(
            "LOGIN", actor=user, target_user=user, request=request,
            reference=user.username or str(user.pk),
            branch_id=serializer.validated_data.get("selected_branch") or None,
            after={"selected_branch": serializer.validated_data.get("selected_branch") or ""},
        )

        # Return user info and the token
        return Response({
            "user": UserSerializer(user, context=self.get_serializer_context()).data,
            "token": token,
            "selected_branch": serializer.validated_data.get("selected_branch") or "",
        })


class LoginBranchOptionsAPI(APIView):
    """Return branch options for a login id. POST only; no serializer required."""

    permission_classes = [permissions.AllowAny]
    authentication_classes = []

    def get(self, request, *args, **kwargs):
        # Allow GET ?login=... as a simple request (no JSON preflight).
        return self.post(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        login_value = request.data.get("login") or request.query_params.get("login")
        if not login_value:
            return Response(
                {
                    "branches": [],
                    "requires_branch": True,
                    "message": "Enter your username, email, or phone number first.",
                },
                status=status.HTTP_200_OK,
            )

        user = User.objects.filter(
            Q(email=login_value) | Q(username=login_value) | Q(phone_number=login_value)
        ).first()

        if not user:
            return Response(
                {
                    "branches": [],
                    "requires_branch": True,
                    "message": "No matching user found.",
                },
                status=status.HTTP_200_OK,
            )

        if user.is_superuser:
            return Response(
                {
                    "branches": [],
                    "requires_branch": False,
                    "message": "Admin user can log in without selecting a branch.",
                },
                status=status.HTTP_200_OK,
            )

        branches = (
            Shop.objects.filter(Q(owner=user) | Q(assigned_users=user))
            .distinct()
            .order_by("name")
        )
        return Response(
            {
                "branches": ShopSerializer(branches, many=True).data,
                "requires_branch": True,
                "message": "Select a branch to continue.",
            },
            status=status.HTTP_200_OK,
        )

    def options(self, request, *args, **kwargs):
        # Ensure preflight always succeeds when the request reaches Django.
        return Response(status=status.HTTP_200_OK)




# Admin Viewset for managing users
class AdminUserManagementViewSet(ChangePasswordMixin, viewsets.ModelViewSet):
    queryset = User.objects.all().order_by('-id')
    serializer_class = AdminUserSerializer
    permission_classes = [permissions.IsAuthenticated, HasTabPermission]
    required_tab = "users"
    filter_backends = [DjangoFilterBackend, SearchFilter]
    filterset_fields = ['is_seller','verified','is_staff']
    search_fields = ['username', 'phone_number', 'email', 'id', 'first_name', 'last_name']

    @staticmethod
    def _delete_owned_shop_data(user):
        owned_shops = Shop.objects.filter(owner=user)
        if not owned_shops.exists():
            return

        purchases = Purchase.objects.filter(shop__in=owned_shops)
        sales = Sale.objects.filter(shop__in=owned_shops)
        customers = Customer.objects.filter(shop__in=owned_shops)
        employees = Employee.objects.filter(shop__in=owned_shops)
        accounts = Account.objects.filter(shop__in=owned_shops)
        currencies = Currency.objects.filter(shop__in=owned_shops)
        purchase_returns = PurchaseReturn.objects.filter(shop__in=owned_shops)
        sale_returns = SaleReturn.objects.filter(shop__in=owned_shops)

        AccountTransfer.objects.filter(
            Q(from_account__in=accounts) | Q(to_account__in=accounts)
        ).delete()
        AccountTransaction.objects.filter(account__in=accounts).delete()
        ExchangeRate.objects.filter(shop__in=owned_shops).delete()

        CustomerBalancePayment.objects.filter(customer__in=customers).delete()
        PurchasePayment.objects.filter(purchase__in=purchases).delete()
        SalePayment.objects.filter(sale__in=sales).delete()

        SaleReturnItem.objects.filter(sale_return__in=sale_returns).delete()
        PurchaseReturnItem.objects.filter(purchase_return__in=purchase_returns).delete()
        SaleReturn.objects.filter(pk__in=sale_returns.values("pk")).delete()
        PurchaseReturn.objects.filter(pk__in=purchase_returns.values("pk")).delete()

        Stock.objects.filter(shop__in=owned_shops).delete()
        SaleItem.objects.filter(sale__in=sales).delete()
        PurchaseItem.objects.filter(purchase__in=purchases).delete()

        Expense.objects.filter(shop__in=owned_shops).delete()
        Advance.objects.filter(shop__in=owned_shops).delete()
        Payroll.objects.filter(shop__in=owned_shops).delete()
        Sale.objects.filter(pk__in=sales.values("pk")).delete()
        Purchase.objects.filter(pk__in=purchases.values("pk")).delete()

        Customer.objects.filter(pk__in=customers.values("pk")).delete()
        Employee.objects.filter(pk__in=employees.values("pk")).delete()
        Supplier.objects.filter(shop__in=owned_shops).delete()
        Product.objects.filter(shop__in=owned_shops).delete()
        Category.objects.filter(shop__in=owned_shops).delete()
        ExpenseCategory.objects.filter(shop__in=owned_shops).delete()
        Unit.objects.filter(shop__in=owned_shops).delete()
        Account.objects.filter(pk__in=accounts.values("pk")).delete()
        Currency.objects.filter(pk__in=currencies.values("pk")).delete()
        Shop.objects.filter(pk__in=owned_shops.values("pk")).delete()

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        return Response(serializer.data, status=201)

    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        return Response(serializer.data)

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        try:
            self._delete_owned_shop_data(instance)
            self.perform_destroy(instance)
        except ProtectedError:
            return Response(
                {
                    "detail": (
                        "This user cannot be deleted because they still own or are linked to "
                        "protected records such as shops, accounts, or transactions. "
                        "Reassign or remove those records first."
                    )
                },
                status=400,
            )
        return Response(status=204)

# User profile management
class UserProfileViewSet(DataRootViewSet):
    serializer_class = UserProfileSerializer
    permission_classes = [permissions.IsAuthenticated]

    def get_object(self):
        """
        Instead of looking up a user by ID, return the currently authenticated user.
        This ensures that users can update only their own profile.
        """
        return self.request.user
