from rest_framework import serializers
from rest_framework import authentication
from mama_care_api.settings import *
from mama_care_api.settings import languageKey
from rest_framework import pagination
from datetime import datetime, timezone
from user.models import *
from .common import *
from subscription.models import *
from basic.models import *

# Create your views here.
# API Key Authorization
class APIKeyAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        apiKey = request.headers.get("apiKey")
        errorMessage = ""
        isRequestAuthenticated = False
        if apiKey is not None:
            if apiKey == SECRET_KEY:
                isRequestAuthenticated = True
            else:
                errorMessage = "In Valid API Key"
        else:
            errorMessage = "No API Key Found"

        if isRequestAuthenticated:
            return None
        else:
            raise serializers.ValidationError({"error": [errorMessage]})


class LoginAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        phone = request.query_params.get("phone")
        password = request.query_params.get("password")
        errorMessage = ""
        isValid = False
        if phone is not None and password is not None:
            selectedList = Parent.objects.filter(phone=phone).filter(
                password=password
            )
            if selectedList.__len__() > 0:
                parent = selectedList[0]
                if parent.phone == phone and parent.password == password:
                    isValid = True
                else:
                    errorMessage = "phone and password is invalid"
            else:
                errorMessage = "No Records found"
        else:
            errorMessage = "phone and password is required"

        if isValid:
            return None
        else:
            raise serializers.ValidationError({"error": [errorMessage]})


# Authentication
class DashboardTokenAuthentication(authentication.BaseAuthentication):

    def checkToken(self, token):
        if token is not None:
            if token != "":
                return True
        return False

    def checkAdminAuth(self, token):
        if token == "admin":
            return True
        return False

    def authenticate(self, request):
        isDashboard = request.headers.get("isDashboard")
        token = request.headers.get("token")
        isAuthenticated = False
        errorMessage = ""
        if self.checkToken(token) == True:
            if isDashboard == "1":
                if self.checkAdminAuth(token) == True:
                    isAuthenticated = True
                else:
                    errorMessage = "In Valid Token"
        else:
            errorMessage = "Token is required"

        if isAuthenticated:
            return None
        else:
            raise serializers.ValidationError({"error": [errorMessage]})


class MobileTokenAuthentication(authentication.BaseAuthentication):

    def tryParseInt(self, val):
        try:
            return int(val)
        except (ValueError, TypeError):
            return None

    def checkLanguage(self, languageId):
        if self.tryParseInt(languageId) is not None:
            val = getLanguageRecord(languageId)
            if val == int(languageId):
                return True
        return False

    def checkToken(self, token):
        if token is not None:
            if token != "":
                return True
        return False
    
    def checkParentAuth(self, token, parentId):
        if self.tryParseInt(parentId) is not None:
            parentTokenList = ParentToken.objects.filter(token=token)
            if parentTokenList.__len__() > 0:
                selected = parentTokenList[0]
                if selected.parentId.id == int(parentId) and selected.token == token:
                    return True
            return False
        return False

    def authenticate(self, request):
        languageId = request.headers.get(languageKey)
        token = request.headers.get("token")
        kwargs = request.parser_context.get("kwargs", {})
        parentIdPK = kwargs.get("pk")
        parentIdFK = request.query_params.get("parentId")

        isAuthenticated = False
        errorMessage = ""

        isPK = False

        parentId = None
        if parentIdPK is not None:
            parentId = parentIdPK
            isPK = True
        elif parentIdFK is not None:
            parentId = parentIdFK

        if parentId is not None:
            if self.checkToken(token) == True:
                if self.checkParentAuth(token, parentId) == True:
                    isAuthenticated = True
                else:
                    errorMessage = "Invalid Token"
                    raise serializers.ValidationError({"error": [errorMessage]})
            else:
                errorMessage = "Token is required"
                raise serializers.ValidationError({"error": [errorMessage]})
        else:
            errorMessage = "Parent Id is required"
            raise serializers.ValidationError({"error": [errorMessage]})

        if isPK == False:
            isLanguageValid = self.checkLanguage(languageId)
            if isAuthenticated:
                if isLanguageValid:
                    return None
                else:
                    errorMessage = "Language is required"
                    raise serializers.ValidationError({"error": [errorMessage]})
            else:
                raise serializers.ValidationError({"error": [errorMessage]})
        return None


class StandardSetPagination(pagination.PageNumberPagination):
    page_size = 20  # default amount records in current page
    page_size_query_param = "page_size"
    max_page_size = (
        1000  # max number of records in current page by using query param above
    )


class SubscriptionPlanMixin:
    def getError(self, currentPlanId,currentPlanKeyName, errorMessage):
        return {
            "subscriptionError": {
                "currentPlanId": currentPlanId,
                "currentPlanKeyName": currentPlanKeyName,
                "errorMessage": [errorMessage],
            }
        }

    def getBasicPlan(self):
        selectedPlanList = SubscriptionPlan.objects.filter(keyName=basicPlanKeyName)
        if selectedPlanList.__len__() > 0:
            return selectedPlanList[0]

    def checkExpirationDate(self, expirationDate):
        """
        expirationDate: ISO 8601 string or datetime
        """
        # Parse ISO string → datetime (supports `2026-01-09T14:30:00` etc.)
        if isinstance(expirationDate, str):
            expiration_dt = datetime.fromisoformat(expirationDate)
        else:
            expiration_dt = expirationDate

        # Use UTC if your backend stores Apple / Google times (recommended)
        if expiration_dt.tzinfo is None:
            expiration_dt = expiration_dt.replace(tzinfo=timezone.utc)

        current_dt = datetime.now(timezone.utc)

        return expiration_dt >= current_dt

    def updateSubscriptionOrder(self,parentId):
        SubscriptionOrder.objects.filter(
            financialProfileId__parentId=parentId).update(isExpired=True)

    def getCurrentSubscriptionPlan(self):
        parentId = self.request.query_params.get("parentId", None)
        if parentId is not None:
            currentList = SubscriptionOrder.objects.filter(
                financialProfileId__parentId=parentId
            ).filter(isExpired=False)
            if currentList.__len__() > 0:
                if self.checkExpirationDate(currentList[0].endDate) == True:
                    return currentList[0].subscriptionPlanId
                else:
                    self.updateSubscriptionOrder(parentId)
                    return self.getBasicPlan()
            else:
                self.updateSubscriptionOrder(parentId)
                return self.getBasicPlan()
        return None

    def checkAIModelPath(self):
        path = self.request.path.replace("/", "")
        path = path.replace("_mobile", "")
        if path == "ai":
            return True
        return False
    
    def checkModelPath(self):
        path = self.request.path.replace("/", "")
        path = path.replace("_mobile", "")
        if path == "child" or path == "user_device":
            return True
        return False

    def get_queryset(self):
        currentPlan = self.getCurrentSubscriptionPlan()
        errorMessage = ""
        isAllow = False
        isSingleRecord = False
        
        page = None
        
        qs = super().get_queryset()

        if self.checkModelPath():
            parentId = self.request.query_params.get("parentId", None)
            if parentId is None:
                errorMessage = "Parent Id is required"
                raise serializers.ValidationError(self.getError(None,None, errorMessage))
            
            model = super().get_queryset().model
            field_names = {f.name for f in model._meta.get_fields()}
            if 'parentId' in field_names:
                qs = qs.filter(parentId=parentId)
            else:
                errorMessage = "Parent Id is not in this model"
                raise serializers.ValidationError(self.getError(None,None, errorMessage))

        page = self.paginate_queryset(qs)

        if currentPlan is not None:
            if currentPlan.isUnLimited:
                if self.checkAIModelPath() == True:
                    if currentPlan.isAllowAIAssist:
                        isAllow = True
                    else:
                        isAllow = False
                else:
                    isAllow = True
            elif currentPlan.isAllowReading:
                isAllow = True
                if page is not None:
                    paginator = self.paginator
                    current_page = paginator.page.number
                    if current_page > 1:
                        if currentPlan.isAllowPaging:
                            isAllow = True
                        else:
                            errorMessage = "Paging is not allowed"

                if self.__class__.__bases__.__len__() > 0:
                    if self.__class__.__bases__[-1].__name__ == "ListAPIView":
                        isSingleRecord = True
                # Block full scan
                # if not qs.query.where.children:
                #     raise RuntimeError("Full table scan is not allowed")
            else:
                errorMessage = "Reading is not allowed"
        else:
            isAllow = False
            errorMessage = "No Plan Found"

        if isAllow == True:
            if isSingleRecord == True:
                if qs.__len__() > 0:
                    return [qs[0]]
            return qs
        else:
            if currentPlan is not None:
                raise serializers.ValidationError(
                    self.getError(currentPlan.id,currentPlan.keyName, errorMessage)
                )
            else:
                raise serializers.ValidationError(self.getError(None,None, errorMessage))


    def perform_create(self, serializer):
        currentPlan = self.getCurrentSubscriptionPlan()
        isAllow = False
        errorMessage = ""
        recordCount = 0

        parentId = self.request.query_params.get("parentId", None)
        if parentId is None:
            errorMessage = "Parent Id is required"
            raise serializers.ValidationError(self.getError(None,None, errorMessage))
        
        if self.checkModelPath():
            parentId = self.request.query_params.get("parentId", None)
            if parentId is None:
                errorMessage = "Parent Id is required"
                raise serializers.ValidationError(self.getError(None,None, errorMessage))
            
            model = super().get_queryset().model
            field_names = {f.name for f in model._meta.get_fields()}
            
            if 'parentId' in field_names:
                qs = super().get_queryset()
                qs = qs.filter(parentId=parentId)
                recordCount = qs.count()
            else:
                errorMessage = "Parent Id is not in this model"
                raise serializers.ValidationError(self.getError(None,None, errorMessage))
            
        else:
            qs = super().get_queryset()
            recordCount = qs.count()

        if currentPlan is not None:
            if currentPlan.isUnLimited:
                if self.checkAIModelPath() == True:
                    if currentPlan.isAllowAIAssist:
                        isAllow = True
                    else:
                        isAllow = False
                else:
                    isAllow = True
            elif currentPlan.isAllowAdding:
                if self.checkModelPath() == True:
                    if recordCount < 2:
                        isAllow = True
                    else:
                        errorMessage = "Maximum Adding is reached"
                else:
                    if recordCount < currentPlan.addingRecordCount:
                        isAllow = True
                    else:
                        errorMessage = "Maximum Adding is reached"
            else:
                errorMessage = "Adding is not allowed"
        else:
            errorMessage = "No Plan Found"

        if isAllow == True:
            if serializer.is_valid():
                serializer.save()
        else:
            if currentPlan is not None:
                raise serializers.ValidationError(
                    self.getError(currentPlan.id,currentPlan.keyName, errorMessage)
                )
            else:
                raise serializers.ValidationError(self.getError(None,None, errorMessage))

    def perform_update(self, serializer):
        currentPlan = self.getCurrentSubscriptionPlan()
        errorMessage = ""
        isAllow = False

        if currentPlan is not None:
            if currentPlan.isUnLimited:
                if self.checkAIModelPath() == True:
                    if currentPlan.isAllowAIAssist:
                        isAllow = True
                    else:
                        isAllow = False
                else:
                    isAllow = True
            elif currentPlan.isAllowEditing:
                isAllow = True
            else:
                errorMessage = "Editing is not allowed"
        else:
            errorMessage = "No Plan Found"

        if isAllow == True:
            if serializer.is_valid():
                serializer.save()
        else:
            if currentPlan is not None:
                raise serializers.ValidationError(
                    self.getError(currentPlan, errorMessage)
                )
            else:
                raise serializers.ValidationError(self.getError(None, errorMessage))

    def perform_destroy(self, model):
        currentPlan = self.getCurrentSubscriptionPlan()
        isAllow = False

        if currentPlan is not None:
            if currentPlan.isUnLimited:
                if self.checkAIModelPath() == True:
                    if currentPlan.isAllowAIAssist:
                        isAllow = True
                    else:
                        isAllow = False
                else:
                    isAllow = True
            elif currentPlan.isAllowDeleting:
                isAllow = True
            else:
                errorMessage = "Deleting is not allowed"
        else:
            errorMessage = "No Plan Found"

        if isAllow == True:
            model.delete()
        else:
            if currentPlan is not None:
                raise serializers.ValidationError(
                    self.getError(currentPlan, errorMessage)
                )
            else:
                raise serializers.ValidationError(self.getError(None, errorMessage))

