from datetime import datetime
import math

from dateutil.relativedelta import relativedelta
from django.db.models import Sum
from django.shortcuts import render
from organisations.models import Organisation, OrganisationBranch
from questbanker_api.utils import get_current_user
from .serializers import *
from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView
from .models import *
from general.helper import date_time_zone_convert
from questbanker_api.utils import send_email
from ledgers.models import OrganisationSubAccount, SystemTransactions
from ledgers.ledgers_helper import generate_reference_no
from .helpers import get_license_charts, sync_organisation_license_status


def _resolve_license_debit_chart(selected_account, existing_license=None, transaction_instance=None):
    candidate_ids = [
        selected_account,
        getattr(existing_license, 'selected_account', None),
        getattr(transaction_instance, 'debit_chart_id', None),
    ]

    for candidate_id in candidate_ids:
        if candidate_id in [None, '', 'null', 'undefined']:
            continue

        debit_chart = OrganisationSubAccount.objects.filter(pk=candidate_id).first()
        if debit_chart:
            return debit_chart, str(debit_chart.pk)

    return None, None


class LicenseSubscriptionView(APIView):
    def get(self, request, format=None):
        response_data = []
        response_data2 = {}
        org_id = self.request.query_params.get("org_id", None)
        organisation_id = get_current_user(self.request, 'organisation_id', None)

        if org_id:
            sync_organisation_license_status(org_id)
        else:
            sync_organisation_license_status()
        
        if org_id:
           license_data = LicenseSubscription.objects.filter(organisation__id=org_id).order_by('id').first()
           response_data2 = LicenseSubscriptionSerializer(license_data).data if license_data else {}
           return Response({"count":len(response_data2), "data":response_data2})
        
        license_data = LicenseSubscription.objects.filter(parent_org__id=organisation_id).order_by('id')
        response_data = LicenseSubscriptionSerializer(license_data, many=True).data        
        return Response({"count":len(response_data), "results":response_data})

    def post(self, request, format=None):
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        organisation_branch_id = get_current_user(request, 'organisation_branch_id', None)
        package = request.data.get('package')
        license_status = request.data.get('status')
        action = request.data.get('action')
        license_id = self.request.query_params.get("license", None)
        existing_license = None
        if license_id:
            existing_license = LicenseSubscription.objects.filter(id=license_id).select_related('transaction', 'organisation').first()
        period_type = request.data.get('period_type')
        grace_period_type = request.data.get('grace_period_type')
        calculation_type = request.data.get('calculation_type')
        license_period = request.data.get('license_period')
        grace_period = request.data.get('grace_period')
        amount = request.data.get('amount')
        transaction_date = request.data.get('record_date')
        org_id = request.data.get('org_id') or (existing_license.organisation_id if existing_license else None)
        payment_method = request.data.get('payment_method')
        selected_account = request.data.get('selected_account')
        transaction_id = self.request.query_params.get("transaction", None)
        license_amount = 0
        remaining_balance = 0
        start_date = None 

        if action == 'deactivate' or action == 'activate' and status:
            try:
                updated_instance = LicenseSubscription.objects.get(id=license_id)
                updated_instance.status = license_status
                updated_instance.force_inactive = (action == 'deactivate')
                updated_instance.license_last_updated_by = self.request.user
                updated_instance.save()
                sync_organisation_license_status(updated_instance.organisation_id)
                return Response({"message": "License status updated successfully."}, status=status.HTTP_200_OK)
            except LicenseSubscription.DoesNotExist:
                return Response({"error": "License not found."}, status=status.HTTP_404_NOT_FOUND)

        if action == 'create' or action == 'update':
            if action == 'update' and not existing_license:
                return Response({"error": "License not found."}, status=status.HTTP_404_NOT_FOUND)

            update_transaction = existing_license.transaction if existing_license else None
            if transaction_id:
                update_transaction = SystemTransactions.objects.filter(id=transaction_id).first() or update_transaction

            if transaction_date:
                record_date = date_time_zone_convert(datetime.strptime(transaction_date, '%Y-%m-%dT%H:%M:%S.%fZ'))
            elif existing_license:
                record_date = existing_license.subcription_date
            else:
                return Response({"error": "record_date is required."}, status=status.HTTP_400_BAD_REQUEST)

            if existing_license and not payment_method:
                payment_method = existing_license.payment_method
        
            organCombinedString = Organisation.objects.filter(pk=org_id).values('name', 'email', 'registration_no')
            if organCombinedString:
                organisation_name = organCombinedString[0]['name']
                organisation_email = organCombinedString[0]['email']
                registration_no = organCombinedString[0]['registration_no']

            credit_chart_code = "4257"
            credit_chart = OrganisationSubAccount.objects.filter(account_code=credit_chart_code, account_organisation=organisation_id).first()
            if credit_chart is None:
                credit_chart = get_license_charts(organisation_id)

            debit_chart_chart, selected_account = _resolve_license_debit_chart(
                selected_account,
                existing_license=existing_license,
                transaction_instance=update_transaction,
            )
            if debit_chart_chart is None:
                return Response({"error": "Please select a valid destination cash account."}, status=status.HTTP_400_BAD_REQUEST)

            reference_no = generate_reference_no(credit_chart.account_line, organisation_id)

            if license_id:
                heading = 'License Subscription updated successfully ' + organisation_name + ' (' + registration_no + ')'
                if not update_transaction:
                    return Response({"error": "Transaction not found."}, status=status.HTTP_404_NOT_FOUND)

                update_transaction.amount = amount
                update_transaction.heading = heading
                update_transaction.reference_no = reference_no
                update_transaction.payment_method = payment_method
                update_transaction.voucher_no = ''
                update_transaction.record_date = record_date
                update_transaction.debit_chart = debit_chart_chart
                update_transaction.credit_chart = credit_chart
                update_transaction.branch = OrganisationBranch.objects.get(pk=organisation_branch_id)
                update_transaction.added_by = self.request.user
                update_transaction.save()

                license_period = math.floor(int(license_period))
                end_date_str = None
                if period_type == 'm':
                    end_date_str = record_date + relativedelta(months=license_period)
                elif period_type == 'd':
                    end_date_str = record_date + relativedelta(days=license_period)
                end_date = end_date_str
                existing_license.package = package
                existing_license.period_type = period_type
                existing_license.grace_period_type = grace_period_type
                existing_license.calculation_types = calculation_type
                existing_license.grace_period = grace_period
                existing_license.amount = amount
                existing_license.selected_account = selected_account
                existing_license.payment_method = payment_method
                existing_license.period = license_period
                existing_license.record_date = record_date
                existing_license.end_date = end_date
                existing_license.subcription_date = record_date
                existing_license.status = 'active'
                existing_license.license_last_updated_by = self.request.user
                existing_license.save()
                sync_organisation_license_status(existing_license.organisation_id)

                organisation = Organisation.objects.filter(pk=existing_license.organisation.id).values('name', 'email')
                if organisation:
                    organisation_name = organisation[0]['name']
                    organisation_email = organisation[0]['email']
                send_email('License has been renewed successfully for ' + organisation_name + ' ', 'License Subscription.', organisation_email)

            else:
                active_members = SavingAccount.objects.filter(customer_branch__branch_organisation=org_id,status='active').count()
                payment_details = LicensePayments.objects.filter(license_subscription=license_id).aggregate(remaining_balance=Sum('remaining_balance'))
                license_period = math.floor(int(license_period))
                end_date_str = None
                if period_type == 'm':
                    end_date_str = record_date + relativedelta(months=license_period)
                elif period_type == 'd':
                    end_date_str = record_date + relativedelta(days=license_period)
                end_date = end_date_str
                start_date = end_date

                if payment_details:
                    balance = payment_details['remaining_balance']
                    if license_id:
                        existing_license = LicenseSubscription.objects.get(id=license_id)
                        if existing_license:
                            if existing_license.calculation_types == 'annual-flat':
                                license_amount = existing_license.amount
                            else:
                                if active_members:
                                    license_amount = (existing_license.revised_amount if existing_license.revised_amount else existing_license.amount) * existing_license.revised_members if existing_license.revised_members else active_members
                                # else:
                                #     license_amount = (existing_license.amount) * existing_license.revised_members
                                remaining_balance = license_amount - balance
                            if remaining_balance <= 0:
                                start_date = existing_license.end_date


                if remaining_balance <=0 or action == 'create':     
                    heading = 'License Subscription successfully created for ' + organisation_name + ' (' + registration_no + ')'
                    saved_transaction = SystemTransactions.objects.create(
                        amount=amount,
                        heading=heading,
                        reference_no=reference_no,
                        payment_method=payment_method,
                        voucher_no='',
                        debit_chart=debit_chart_chart,
                        credit_chart=credit_chart,
                        branch=OrganisationBranch.objects.get(pk=organisation_branch_id),
                        added_by=self.request.user
                    )
                    if saved_transaction:
                        license_sub=LicenseSubscription(
                            period_type=period_type,
                            package=package,
                            calculation_types=calculation_type,
                            period=license_period,
                            grace_period=grace_period,
                            amount=amount,
                            organisation=Organisation.objects.get(pk=org_id),
                            license_added_by=self.request.user,
                            record_date=record_date,
                            parent_org=Organisation.objects.get(pk=organisation_id),
                            grace_period_type=grace_period_type,
                            selected_account=selected_account,
                            payment_method=payment_method,
                            status='active',
                            start_date = start_date,
                            end_date   = end_date,
                            transaction=saved_transaction
                        )
                        license_sub.save()
                        sync_organisation_license_status(license_sub.organisation_id)

                        send_email('License has been created successfully for ' + organisation_name + ' ', 'License Subscription.', organisation_email)

        return Response({"status": "success"}, status=status.HTTP_200_OK)
    
class LicensePaymentsView(APIView):        
    def post(self,request,format=None):
        record_date = request.data.get('record_date')
        license = request.data.get('license')
        package    = request.data.get('package')
        calculation_type  = request.data.get('calculation_type')
        amount = request.data.get('amount')
        period_type = request.data.get('period_type')
        record_date = date_time_zone_convert(datetime.strptime(request.data.get('record_date'), '%Y-%m-%dT%H:%M:%S.%fZ'))
        org_id      = request.data.get('organisation')
        payment_method = request.data.get('payment_method')
        selected_account = request.data.get('selected_account')
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        organisation_branch_id = get_current_user(request, 'organisation_branch_id',None) 
        license_period  = request.data.get('license_period')
        revised_members = request.data.get('revised_members')
        revised_amount = request.data.get('revised_amount')
        balance = 0
        updated_subscription = LicenseSubscription.objects.filter(pk=license).select_related('transaction').first()  
        if license and not updated_subscription:
            return Response({"error": "License not found."}, status=status.HTTP_404_NOT_FOUND)
        active_members = SavingAccount.objects.filter(customer_branch__branch_organisation=org_id,status='active').count()
        payment_details = LicensePayments.objects.filter(license_subscription=license).aggregate(paid_amount=Sum('amount_paid'))
        license_period = math.floor(int(license_period))
        end_date_str = None
        if period_type == 'd':
            end_date_str = record_date + relativedelta(days=license_period)
        elif period_type == 'm':
            end_date_str = record_date + relativedelta(months=license_period)
        if balance <= 0:
            end_date = end_date_str
        else:
            end_date=None             
      
        if license:
            organCombinedString = Organisation.objects.filter(pk=org_id).values('name', 'email','registration_no')
            if organCombinedString:
                organisation_name = organCombinedString[0]['name']
                organisation_email = organCombinedString[0]['email']
                registration_no =  organCombinedString[0]['registration_no']
            credit_chart_code = "4257"
            credit_chart = OrganisationSubAccount.objects.filter(account_code=credit_chart_code, account_organisation=organisation_id).first()
            if credit_chart is None:
                credit_chart = get_license_charts(organisation_id) 
            if updated_subscription and not payment_method:
                payment_method = updated_subscription.payment_method
            debit_chart_chart, selected_account = _resolve_license_debit_chart(
                selected_account,
                existing_license=updated_subscription,
                transaction_instance=updated_subscription.transaction if updated_subscription else None,
            )
            if debit_chart_chart is None:
                return Response({"error": "Please select a valid destination cash account."}, status=status.HTTP_400_BAD_REQUEST)
            reference_no = generate_reference_no(credit_chart.account_line, organisation_id)
            user = self.request.user                  
          
            # if package or calculation types are updated
            if updated_subscription:
                updated_subscription.calculation_types = calculation_type
                updated_subscription.package = package
                updated_subscription.license_last_updated_by = user
                updated_subscription.revised_members=revised_members
                updated_subscription.revised_amount=revised_amount
                updated_subscription.selected_account = selected_account
                updated_subscription.payment_method = payment_method
                updated_subscription.status = 'active'
                if end_date is not None:
                    updated_subscription.end_date = end_date
                saved_license=updated_subscription.save()
                sync_organisation_license_status(updated_subscription.organisation_id)
                if saved_license:
                    if payment_details:
                        amount_paid = payment_details['paid_amount']
                        new_amount = updated_subscription.revised_amount if updated_subscription.revised_amount else updated_subscription.amount
                        if amount_paid is None :
                            if calculation_type == 'annual-flat':
                                balance = float(new_amount) - float(amount)
                            else:
                                balance = (float(new_amount)) * active_members - float(amount)
                        else:
                            if calculation_type == 'annual-flat':
                                remaining_balance = new_amount - amount_paid
                                balance = remaining_balance - float(amount)
                            else:
                                remaining_balance = (new_amount * active_members) - amount_paid
                                balance = remaining_balance - float(amount) 
                        if debit_chart_chart:
                            heading = 'License Payment for '+ organisation_name +' ('+ registration_no +')'
                            saved_transaction = SystemTransactions.objects.create(
                                amount=amount,
                                heading=heading, 
                                reference_no=reference_no,
                                payment_method=payment_method, 
                                voucher_no='',
                                debit_chart=debit_chart_chart,
                                credit_chart=credit_chart,
                                branch=OrganisationBranch.objects.get(pk=organisation_branch_id), 
                                added_by=user)
                            if saved_transaction:
                                license_payment = LicensePayments(
                                license_subscription=LicenseSubscription.objects.get(pk=license),
                                payment_method=payment_method,
                                selected_account=selected_account,
                                amount_paid=amount,
                                remaining_balance=balance,
                                license_date = updated_subscription.end_date,
                                record_date=record_date,
                                transaction = saved_transaction,
                                payment_added_by=user
                                )
                                license_payment.save()
                                send_email('License has been renewed successfully for ' + organisation_name + ' ', 'License Subscription.', organisation_email)

            # if package or calculation types are not updated  
            if debit_chart_chart:
                heading = 'License Payment for '+ organisation_name +' ('+ registration_no +')'
                saved_transaction = SystemTransactions.objects.create(
                    amount=amount,
                    heading=heading, 
                    reference_no=reference_no,
                    payment_method=payment_method, 
                    voucher_no='',
                    debit_chart=debit_chart_chart,
                    credit_chart=credit_chart,
                    branch=OrganisationBranch.objects.get(pk=organisation_branch_id), 
                    added_by=self.request.user)
                if saved_transaction:
                    license_payment = LicensePayments(
                    license_subscription=LicenseSubscription.objects.get(pk=license),
                    payment_method=payment_method,
                    selected_account=selected_account,
                    amount_paid=amount,
                    remaining_balance=balance,
                    record_date=record_date,
                    license_date = updated_subscription.end_date,
                    transaction = saved_transaction,
                    payment_added_by=user
                    )
                    license_payment.save()
                    send_email('License has been renewed successfully for ' + organisation_name + ' ', 'License Subscription.', organisation_email)

        return Response({"status":"success"},status=status.HTTP_200_OK)
    


