from mobileapp.serializers import VslaLoanPaymentSerializer, VslaLoanSettingsSerializer, VslaLoansSerializer, VslaSavingsSerializer, VslaShareSettingsSerializer, VslaSharesSerializer
from rest_framework import viewsets
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.db.models import Q, Sum

from savings.savings_bal_helper import get_account_balance
from .serializers import *
from customers.models import GroupMembership
from savings.models import GroupSavingTransaction, SavingAccount, SavingAccountTransactions
from customers.serializers import CustomerSerializer, CustomerMembershipSerializer
from questbanker_api.utils import get_current_user
from exservices.exservices_helper import send_mm_pin
import random
from savings.serializers import GroupSavingTransactionSerializer, SavingAccountStatementSerializer
from mobileapp.models import VslaLoanPayments, VslaLoanSettings, VslaLoans, VslaMemberShares, VslaMembership,VslaSavings, VslaShareSettings

from organisations.models import *
from license.helpers import get_organisation_access_state

class MobileBankingSubscriptionView(viewsets.ModelViewSet):
    serializer_class = MobileBankingSubscriptionSerializer
    # http_method_names = ['get']

    def get_queryset(self):
        organisation_id = get_current_user(
            self.request, 'organisation_id', None)
        if organisation_id:
            customer_id = self.request.GET.get('customer', None)
            if customer_id:
                return MobileBankingSubscription.objects.filter(customer_id=customer_id, customer__customer_branch__branch_organisation__id=organisation_id)

            return MobileBankingSubscription.objects.filter(customer__customer_branch__branch_organisation__id=organisation_id)

    def perform_create(self, serializer):
        # Generate pin of length 4
        pin = random.randint(pow(10, 3), pow(10, 4) - 1)
        old_telephone = self.request.data.get('old_contact', None)
        customer_id = self.request.data.get('customer_id', 0)
        telephone_no = self.request.data.get('telephone')
        status = self.request.data.get('status')
        reset_pin = self.request.data.get('reset_pin')

        # clean telephone number
        telephone_no = '0' + telephone_no[-9:]
        # check if subscription exists
        status = True if status == 'active' else False
        subscription = MobileBankingSubscription.objects.filter(
            customer_id=customer_id, telephone_no=old_telephone).first()
        if subscription:
            subscription.telephone_no = telephone_no
            subscription.active = status
          
            if subscription and status == True and reset_pin == True:
                subscription.pin = pin
                
                sms_text = "Dear "+subscription.customer.name.capitalize()+", Your mobile banking pin has been reset "+subscription.customer.customer_branch.branch_organisation.name.upper() + \
                    " mobile banking\n Dial *284*55#. Access MEM NO: " + \
                    subscription.customer.member_number+" New PIN: "+str(pin)
                send_mm_pin(subscription, sms_text,self.request.user) 
            subscription.save()
        else:
            subscription = serializer.save(
                customer_id=customer_id, pin=pin, active=status, telephone_no=telephone_no, added_by_id=self.request.user.id)
            if subscription:
                sms_text = "Dear "+subscription.customer.name.capitalize()+", Welcome to "+subscription.customer.customer_branch.branch_organisation.name.upper() + \
                    " mobile banking\n Dial *284*55#. Access MEM NO: " + \
                    subscription.customer.member_number+" PIN: "+str(pin)
                send_mm_pin(subscription, sms_text,self.request.user)

class MMBankingLoginView(APIView):
    authentication_classes = []
    permission_classes = []

    def post(self, request, format=None):
        response_status = status.HTTP_200_OK
        message = {
            'status': 'failed',
            'message': 'Invalid Logins'
        }
        pin = self.request.data.get('pin', None)
        member_number = self.request.data.get('member_number')

        subscription = MobileBankingSubscription.objects.filter(Q(customer__member_number=member_number, pin=pin, active=True) | Q(
            customer__old_member_number=member_number, pin=pin, active=True)).first()
        if subscription:
            organisation = getattr(getattr(subscription.customer, 'customer_branch', None), 'branch_organisation', None)
            access_state = get_organisation_access_state(organisation=organisation, force_sync=True)
            if not access_state['allowed']:
                return Response({
                    'status': False,
                    'message': access_state['message']
                }, status=status.HTTP_403_FORBIDDEN)

            message = {
                'status': 'success',
                'customer': CustomerSerializer(subscription.customer).data
            }
            response_status = status.HTTP_200_OK

        return Response(message, response_status)


class MMBankingGroupMembersView(APIView):
    authentication_classes = []
    permission_classes = []

    def get(self, request, format=None):
        response_status = status.HTTP_404_NOT_FOUND
        message = {
            'status': 'failed',
            'message': 'Invalid Group Details'
        }
        member_number = request.GET.get('member_number', None)
        subscription = MobileBankingSubscription.objects.filter(Q(customer__member_number=member_number, active=True) | Q(
            customer__old_member_number=member_number, active=True)).first()
        if subscription:
            members = GroupMembership.objects.filter(
                group_id=subscription.customer.id, active=True)
            message = {
                'status': 'success',
                'count': len(members),
                'members': CustomerMembershipSerializer(members, many=True).data
            }
            response_status = status.HTTP_200_OK

        return Response(message, response_status)


class MMBankingGroupMemberBalancesView(APIView):
    authentication_classes = []
    permission_classes = []

    def post(self, request, format=None):
        response_status = status.HTTP_404_NOT_FOUND
        message = {
            'status': 'failed',
            'message': 'Invalid Group Details'
        }
        member_number = self.request.data.get('member_number', None)

        subscription = MobileBankingSubscription.objects.filter(Q(customer__member_number=member_number, active=True) | Q(
            customer__old_member_number=member_number, active=True)).first()
        if subscription:

            member_balances = []
            account = SavingAccount.objects.filter(
                account_customer=subscription.customer).first()
            chart = account.account_product.accounts_chart.id
            if account:
                memberships = GroupMembership.objects.filter(group=account.account_customer, active=True)
                if memberships:
                    for membership in memberships:
                        balance_bf  = 0
                        filter_array    = {"savings__customer_account":account,"membership":membership,"savings__transaction__transaction_type":"normal"}
                        filter_array_bf = {"savings__customer_account":account,"membership":membership,"savings__transaction__transaction_type":"normal"}
                        
                        group_savings = GroupSavingTransaction.objects.filter(**filter_array)
                        group_savings_transactions_bf = GroupSavingTransaction.objects.filter(**filter_array_bf)

                        if len(group_savings_transactions_bf) > 0:
                                transactons_bf  = GroupSavingTransactionSerializer(group_savings_transactions_bf, many=True).data
                                for transacton_bf in transactons_bf:
                                    if chart == float(transacton_bf['credit_chart']):
                                        balance_bf += float(transacton_bf['amount'])
                                    else:
                                        balance_bf -= float(transacton_bf['amount'])
            
                        if group_savings:
                            transactons = GroupSavingTransactionSerializer(group_savings, many=True).data
                            balance = 0
                            money_in = 0
                            money_out = 0
                            for transacton in transactons:
                                if int(transacton['credit_chart']) == int(chart):
                                    balance += float(transacton['amount'])
                                    money_in += float(transacton['amount'])
                                else:
                                    balance -= float(transacton['amount'])
                                    money_out += float(transacton['amount'])

                            member_balances.append({
                                "id":membership.member.id,
                                'name': membership.member.name,
                                'old_member_number': membership.member.old_member_number,
                                'member_number': membership.member.member_number,
                                'money_in': money_in,
                                'money_out': money_out,
                                'balance': balance,
                                "transactons":transactons,
                                "chart":chart
                            })
                    
                    message = {"count":len(member_balances), "members":member_balances, 'status': 'success'}
            return Response(message, status=status.HTTP_200_OK)



class MMBankingGroupMemberSharesView(APIView):
    authentication_classes = []
    permission_classes = []

    def post(self, request, format=None):
        response_status = status.HTTP_404_NOT_FOUND
        message = {
            'status': 'failed',
            'message': 'Invalid Group Details'
        }
        member_number = self.request.data.get('member_number', None)

        subscription = MobileBankingSubscription.objects.filter(Q(customer__member_number=member_number, active=True) | Q(
            customer__old_member_number=member_number, active=True)).first()
        if subscription:
            member_balances = []
            members = GroupMembership.objects.filter(
                group_id=subscription.customer.id, active=True)
            for member in members:
                shares_amount = 0
                shares_value = 0
                # member_transactions = GroupSavingTransaction.objects.filter(membership=member).values_list('savings__transaction_id', flat=True)
                # total_in = SystemTransactions.objects.filter(id__in=member_transactions).aggregate(total=Sum('amount'))['total']
                # if total_in:
                #     shares_amount = total_in

                # total_out = SystemTransactions.objects.filter(id__in=member_transactions).aggregate(total=Sum('amount'))['total']
                # if total_out:
                #     shares_value = total_in

                member_balances.append({
                    'name': member.member.name,
                    'old_member_number': member.member.old_member_number,
                    'member_number': member.member.member_number,
                    'shares_amount': shares_amount,
                    'shares_value': shares_value,
                })

            message = {
                'status': 'success',
                'count': len(member_balances),
                'members': member_balances
            }
            response_status = status.HTTP_200_OK

        return Response(message, response_status)


class VslaMMBankingGroupMemberBalancesView(APIView):

    def post(self, request, format=None):
        message = {
            'status': 'failed',
            'message': 'Invalid Group Details'
        }
        group = self.request.data.get('group', None)
        start = self.request.data.get('from_date', None)
        end = self.request.data.get('to_date', None)
        member_balances = []


        memberships=VslaMembership.objects.filter(group_id=group,active=True)
        if memberships:
                    for membership in memberships:
                        filter_array    = {"membership":membership}
                        mid=membership.id
                        
                        group_savings = VslaSavings.objects.filter(membership=mid,record_date__date__gte=start, record_date__date__lte=end)
                        group_loans = VslaLoans.objects.filter(membership=mid,record_date__date__gte=start, record_date__date__lte=end)
                        group_shares = VslaMemberShares.objects.filter(membership=mid,record_date__date__gte=start, record_date__date__lte=end)
                        balance = 0
                        money_in = 0
                        money_out = 0
                        princ_paid=0
                        int_paid=0
                        penalty_paid=0
                        share_bal=0
                        share_amount=0
                        transactons=0
                        shares=[]
                        savings=[]
                        transactonspay=[]
            
                        if group_savings:
                            transactons = VslaSavingsSerializer(group_savings, many=True).data
                           
                            for transacton in transactons:
                                if transacton['transaction_type'] == 'cr':
                                    balance += float(transacton['amount'])
                                    money_in += float(transacton['amount'])
                                else:
                                    balance -= float(transacton['amount'])
                                    money_out += float(transacton['amount'])

                        if group_loans:
                           loans = VslaLoansSerializer(group_loans, many=True).data
                           
                           for loan in loans:
                               loans_pay = VslaLoanPayments.objects.filter(loan_application=loan['id'],payment_date__date__gte=start, payment_date__date__lte=end)
                               transactonspay = VslaLoanPaymentSerializer(loans_pay, many=True).data
                               for pay in transactonspay:
                                   if pay['transaction_type'] == 'cr':
                                      princ_paid += float(pay['princ_paid'])
                                      int_paid += float(pay['int_paid'])
                                      penalty_paid += float(pay['penalty_paid'])
                                   else:
                                       princ_paid -= float(pay['princ_paid'])
                                       int_paid -= float(pay['int_paid'])
                                       penalty_paid -= float(pay['penalty_paid'])
                        
                        if group_shares:
                           shares = VslaSharesSerializer(group_shares, many=True).data  
                           for share in shares:
                               if share['transaction_type'] == 'cr':
                                  share_bal += float(share['shares'])
                                  share_amount += float(share['amount'])
                               else:
                                   share_bal -= float(share['shares'])
                                   share_amount -= float(share['amount'])
                        
                    
                        member_balances.append({
                                "id":membership.id,
                                'name': membership.name,
                                'old_member_number': membership.member_number,
                                'member_number': membership.member_number,
                                'money_in': money_in,
                                'money_out': money_out,
                                'balance': balance,
                                'savings':transactons,

                                'loans': transactonspay,
                                'princ_paid': princ_paid,
                                'int_paid': int_paid,
                                'penalty_paid': penalty_paid,
                                'shares':shares,
                                "share_amount":share_amount,
                                'share_bal': share_bal,
                                'penalty_paid': penalty_paid,
                                
                            })
                    
                    message = {"count":len(member_balances), "members":member_balances, 'status': 'success'}
        return Response(message, status=status.HTTP_200_OK)
    


class VslaMMMemberShareBalancesView(APIView):

    def post(self, request, format=None):
        message = {
            'status': 'failed',
            'message': 'Invalid Group Details'
        }
        group = self.request.data.get('group', None)
        start = self.request.data.get('from_date', None)
        end = self.request.data.get('to_date', None)
        member_balances = []


        memberships=VslaMembership.objects.filter(group_id=group,active=True)
        if memberships:
                    for membership in memberships:
                        mid=membership.id
                        group_shares = VslaMemberShares.objects.filter(membership=mid,record_date__date__gte=start, record_date__date__lte=end)
            
                        if group_shares:
                            transactons = VslaSharesSerializer(group_shares, many=True).data
                            balance = 0
                            shares  =0
                            money_in = 0
                            money_out = 0
                            shares_in = 0
                            shares_out = 0
                            for transacton in transactons:
                                if transacton['transaction_type'] == 'cr':
                                    balance += float(transacton['amount'])
                                    shares += float(transacton['shares'])
                                    money_in += float(transacton['amount'])
                                    shares_in += float(transacton['shares'])
                                else:
                                    balance -= float(transacton['amount'])
                                    shares -= float(transacton['shares'])
                                    money_out += float(transacton['amount'])
                                    shares_out += float(transacton['shares'])

                            member_balances.append({
                                "id":membership.id,
                                'name': membership.name,
                                'old_member_number': membership.member_number,
                                'member_number': membership.member_number,
                                'money_in': money_in,
                                'money_out': money_out,
                                'shares_in': shares_in,
                                'shares_out': shares_out,
                                'balance': balance,
                                 'shares': shares,
                                "transactons":transactons,
                            })
                    
                    message = {"count":len(member_balances), "members":member_balances, 'status': 'success'}
        return Response(message, status=status.HTTP_200_OK)



class VslaSharesSettingsView(APIView):

    def post(self, request, format=None):
        response_status = status.HTTP_200_OK
        message = {
            'status': 'failed',
            'message': 'Invalid Data'
        }
        group = self.request.data.get('group')
        aid = int(self.request.data.get('id'))
        min_shares = self.request.data.get('min_shares')
        max_shares = self.request.data.get('max_shares')
        share_cap = self.request.data.get('share_cap')
        share_value = self.request.data.get('share_value')
      
        settings = VslaShareSettings.objects.filter(group_id=group,  active=True).first()
 
        if settings and aid > 0:
            settings = VslaShareSettings.objects.filter(Q(group_id=group,  active=True)).update(**request.data) 
        if not settings:
            settings = VslaShareSettings.objects.update_or_create(
           min_shares=min_shares, share_value=share_value,max_shares=max_shares,share_cap=share_cap,group_id=group,added_by_id=self.request.user.id,
        defaults={ 'group_id': group,'min_shares': min_shares,'max_shares':max_shares,'share_cap':share_cap,'share_value':share_value},
              )
            
        config = VslaShareSettings.objects.filter(Q(group_id=group,  active=True)).first()
        if config:
            message = {
                'status': 'success',
                'customer': VslaShareSettingsSerializer(config).data
            }
            response_status = status.HTTP_200_OK

        return Response(message, response_status)
    


class VslaloanSettingsActionsView(APIView):

    def post(self, request, format=None):
        response_status = status.HTTP_200_OK
        message = {
            'status': 'failed',
            'message': 'Invalid Data'
        }

        group = self.request.data.get('group')
        id = self.request.data.get('id')
        int_rate = self.request.data.get('int_rate')
        int_method = self.request.data.get('int_method')
        loan_period = self.request.data.get('loan_period')
        period_type = self.request.data.get('period_type')
        min_amount = self.request.data.get('min_amount')
        max_amount = self.request.data.get('max_amount')
        name = self.request.data.get('name')
      
        if id:
         VslaLoanSettings.objects.filter(Q(id=id,  active=True)).update(**request.data) 
        else:
          VslaLoanSettings.objects.update_or_create(
           name=name,int_rate=int_rate,min_amount=min_amount,max_amount=max_amount, int_method=int_method,loan_period=loan_period,period_type=period_type,group_id=group,added_by_id=self.request.user.id,
        defaults={ 'group_id': group},
              )
            
        config = VslaLoanSettings.objects.filter(Q(group_id=group,  active=True)).first()
        if config:
            message = {
                'status': 'success',
                'settings': VslaLoanSettingsSerializer(config).data
            }
            response_status = status.HTTP_200_OK

        return Response(message, response_status)




class MMVslaloanActionsView(APIView):

    def post(self, request, format=None):
        response_status = status.HTTP_200_OK
        message = {
            'status': 'failed',
            'message': 'Invalid Data'
        }

        group = self.request.data.get('group')
        id = self.request.data.get('aid', None)
        int_rate = self.request.data.get('int_rate')
        int_method = self.request.data.get('int_method')
        loan_product = self.request.data.get('loan_product')
        loan_status = self.request.data.get('loan_status')
        amount = self.request.data.get('amount')
        reason = self.request.data.get('reason')
        membership= self.request.data.get('membership')
      
        if id:
            VslaLoans.objects.filter(Q(id=id,  active=True)).update(**request.data) 
        else:
            VslaLoans.objects.update_or_create(
           int_rate=int_rate,amount=amount,loan_product=loan_product, int_method=int_method,loan_status=loan_status,reason=reason,membership_id=membership,group_id=group,added_by_id=self.request.user.id,
        defaults={ 'group_id': group},
              )
            
        config = VslaLoans.objects.filter(Q(group_id=group,  active=True)).first()
        if config:
            message = {
                'status': 'success',
                'settings': VslaLoansSerializer(config).data
            }
            response_status = status.HTTP_200_OK

        return Response(message, response_status)




class VslaLoanProfileView(APIView):


    def post(self, request, format=None):
        response_status = status.HTTP_404_NOT_FOUND
        message = {
            'status': 'failed',
            'message': 'Invalid Group Details'
        }
        
        loan_id = self.request.data.get('loan_id', None)
        start = self.request.data.get('from_date', None)
        end = self.request.data.get('to_date', None)
        member_balances = []

        #payment=VslaLoanPayments.objects.filter(loan_application=loan_id)
        payment=VslaLoanPayments.objects.filter(loan_application=loan_id,payment_date__date__gte=start, payment_date__date__lte=end)
        
        if payment:
            transactons = VslaLoanPaymentSerializer(payment, many=True).data
            princ_paid_in = 0
            int_paid_in=0
            penalty_paid_in = 0
            for transacton in transactons:
                if transacton['transaction_type'] == 'cr':
                   
                   # balance += float(transacton['princ_paid'])
                   # money_in += float(transacton['princ_paid'])
                    princ_paid_in += float(transacton['princ_paid'])
                    int_paid_in += float(transacton['int_paid'])
                    penalty_paid_in += float(transacton['penalty_paid'])
                else:
                    #balance -= float(transacton['princ_paid'])
                    # money_out += float(transacton['princ_paid'])
                    # money_in -= float(transacton['princ_paid'])
                   
                    princ_paid_in -= float(transacton['princ_paid'])
                    int_paid_in -= float(transacton['int_paid'])
                    penalty_paid_in -= float(transacton['penalty_paid'])
                   
            member_balances.append({
                   # 'money_in': money_in,
                   # 'money_out': money_out,
                    'princ_paid_in': princ_paid_in,
                    'int_paid_in': int_paid_in,
                    'penalty_paid_in': penalty_paid_in,
                    #'money_in': money_in,
                    #'balance': balance,
                    "transactons":transactons,
                })
             
        message = {"count":len(member_balances), "members":member_balances, 'status': 'success'}
        return Response(message, status=status.HTTP_200_OK)
    
    

class MMAccountTransactionsView(APIView):

    def post(self, request, format=None):
        '''
        Member statement.
        '''
        
        data = {
            'balance': 0,
             'balance_bf': 0,
            'min_balance': 0,
            'chart': 0,
            'transactions': []
        }
        start = self.request.data.get('from_date', None)
        end = self.request.data.get('to_date', None)
        account_id = self.request.data.get('account_id', None)
        account = SavingAccount.objects.filter(id=account_id)
        
        blocked_amount    = 0
        withheld_amount   = 0
        totalBal          =0
        pTotalIn          =0
        pTotalOut         =0

        if len(account):
            account = account[0]
            #Compute Summary
            if end:
                end_bal   = get_account_balance(account,end)
                blocked_amount    = end_bal['blocked_amount']
                withheld_amount   = end_bal['with_held']
            
            # Generate balance BF
            money_in = SavingAccountTransactions.objects.filter(customer_account_id=account, transaction__record_date__date__lt=start,
                                                                transaction__credit_chart=account.account_product.accounts_chart).aggregate(total=Sum('transaction__amount'))['total']
            if not money_in:
                money_in = 0

            money_out = SavingAccountTransactions.objects.filter(customer_account_id=account, transaction__record_date__date__lt=start,
                                                                 transaction__debit_chart=account.account_product.accounts_chart).aggregate(total=Sum('transaction__amount'))['total']
            if not money_out:
                money_out = 0
                

            # Period transactions
            transactions = SavingAccountTransactions.objects.filter(
                customer_account_id=account, transaction__record_date__date__gte=start, transaction__record_date__date__lte=end).order_by('transaction__record_date__date', 'id')
                
            for trans in SavingAccountStatementSerializer(transactions, many=True).data:
                        
                 if account.account_product.accounts_chart.id == float(trans['transaction']['credit_chart']):
                                        totalBal += float(trans['transaction']['amount'])
                                        pTotalIn  += float(trans['transaction']['amount'])
                 else:
                                        totalBal -= float(trans['transaction']['amount'])
                                        pTotalOut +=float(trans['transaction']['amount'])
                                        

            data = {
                'pTotalIn':pTotalIn,
                'pTotalOut':pTotalOut,
                'balance':totalBal,
                'balance_bf': money_in - money_out,
                'min_balance': account.account_product.min_balance,
                'chart': account.account_product.accounts_chart.id,
                'transactions': SavingAccountStatementSerializer(transactions, many=True).data,
                'blocked_amount':blocked_amount,
                'withheld_amount':withheld_amount
            }

        return Response(data, status=status.HTTP_200_OK)
    
