from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import AllowAny
from savings.models import SavingAccount, SavingAccountTransactions
from savings.savings_bal_helper import get_account_balance
from loans.models import LoanApplication, LoanRepaymentSchedule, LoanPayments
from shares.models import SharesTransaction, ShareHolders, SharesSettings, ShareDividendCustomers
from shares.shares_balance_helper import get_client_shares_balance
from customers.models import Customer
from django.db.models import Q, Sum
from django.db import connection
from datetime import date

class MobileSavingsAccountDetailView(APIView):
    """Get detailed savings account info with last 10 transactions"""
    authentication_classes = []
    permission_classes = [AllowAny]
    
    def get(self, request, account_id, format=None):
        try:
            account = SavingAccount.objects.get(
                id=account_id,
                status='active'
            )
        except SavingAccount.DoesNotExist:
            return Response({
                'status': False,
                'message': 'Account not found'
            }, status=status.HTTP_404_NOT_FOUND)

        # Get balance info - this returns the raw data
        balance_info = get_account_balance(account)
        
        # Helper to convert balance values
        def clean_balance(val):
            if isinstance(val, str):
                return float(val.replace(',', ''))
            return float(val) if val else 0.0
        
        # Get balance components using correct keys
        # balance_actual = total deposits - total withdrawals (raw balance)
        # balance_raw = balance after deducting min_balance, blocked, withheld
        raw_balance = clean_balance(balance_info.get('balance_actual', 0))
        min_balance = account.account_product.min_balance if account.account_product.min_balance else 0
        blocked_amount = clean_balance(balance_info.get('blocked_amount', 0))
        withheld_amount = clean_balance(balance_info.get('with_held', 0))
        
        # Calculate available balance: raw_balance - (min_balance + blocked + withheld)
        available_balance = raw_balance - (min_balance + blocked_amount + withheld_amount)
        
        # Get last 10 transactions
        transactions = SavingAccountTransactions.objects.filter(
            customer_account=account
        ).select_related('transaction').order_by('-transaction__record_date')[:10]
        
        transactions_data = []
        for trans in transactions:
            chart_id = account.account_product.accounts_chart.id
            is_credit = trans.transaction.credit_chart.id == chart_id
            
            transactions_data.append({
                'id': trans.transaction.id,
                'date': trans.transaction.record_date,
                'description': trans.transaction.heading,
                'amount': float(trans.transaction.amount),
                'type': 'credit' if is_credit else 'debit',
                'balance': float(trans.transaction.amount)  # Running balance would need calculation
            })

        return Response({
            'status': True,
            'data': {
                'account_id': account.id,
                'account_number': account.account_no,
                'product_name': account.account_product.product_name,
                'balance': raw_balance,
                'min_balance': min_balance,
                'blocked_amount': blocked_amount,
                'withheld_amount': withheld_amount,
                'available_balance': available_balance,
                'chart': balance_info.get('chart'),
                'transactions': transactions_data
            }
        }, status=status.HTTP_200_OK)

class MobileLoanAccountDetailView(APIView):
    """Get detailed loan account info with last 10 transactions"""
    authentication_classes = []
    permission_classes = [AllowAny]
    
    def get(self, request, loan_id, format=None):
        try:
            loan = LoanApplication.objects.select_related(
                'loan_application_product',
                'loan_officer',
                'customer',
                'loan_application_disbursement'
            ).get(id=loan_id)
        except LoanApplication.DoesNotExist:
            return Response({
                'status': False,
                'message': 'Loan not found'
            }, status=status.HTTP_404_NOT_FOUND)

        # Get accurate balance from database function
        as_at = date.today().strftime('%Y-%m-%d')
        with connection.cursor() as cursor:
            cursor.execute(
                "SELECT princ_paid, int_paid, penalty_paid, total_principal_expected, total_interest_expected "
                "FROM loan_repayment_func(%s) WHERE id = %s;",
                [as_at, loan.id]
            )
            row = cursor.fetchone()
            
            if row:
                princ_paid, int_paid, penalty_paid, total_principal_expected, total_interest_expected = row
                principal_balance = (total_principal_expected or 0) - (princ_paid or 0)
                interest_balance = (total_interest_expected or 0) - (int_paid or 0)
                total_balance = principal_balance + interest_balance + (penalty_paid or 0)
            else:
                princ_paid = 0
                int_paid = 0
                penalty_paid = 0
                total_principal_expected = loan.loan_amount
                total_interest_expected = 0
                principal_balance = loan.loan_amount
                interest_balance = 0
                total_balance = loan.loan_amount

        # Get disbursement info
        disbursement = None
        disbursement_date = None
        loan_start_date = None
        if hasattr(loan, 'loan_application_disbursement'):
            disbursement = loan.loan_application_disbursement
            disbursement_date = disbursement.loan_disbursement_date
            loan_start_date = disbursement.loan_start_date

        # Get next payment due
        next_schedule = LoanRepaymentSchedule.objects.filter(
            loan_application=loan,
            status='active',
            expected_date__gte=date.today(),
            deleted=False
        ).order_by('expected_date').first()

        next_payment_data = None
        if next_schedule:
            next_payment_data = {
                'due_date': next_schedule.expected_date,
                'principal_expected': float(next_schedule.principal_expected),
                'interest_expected': float(next_schedule.interest_expected),
                'total_expected': float(next_schedule.total_payment)
            }

        # Get last 10 loan payments
        payments = LoanPayments.objects.filter(
            loan_application=loan,
            deleted=False
        ).select_related('loan_main_transaction').order_by('-payment_date')[:10]
        
        transactions_data = []
        for payment in payments:
            transactions_data.append({
                'id': payment.id,
                'date': payment.payment_date,
                'principal_paid': float(payment.princ_paid or 0),
                'interest_paid': float(payment.int_paid or 0),
                'penalty_paid': float(payment.penalty_paid or 0),
                'total_amount': float((payment.princ_paid or 0) + (payment.int_paid or 0) + (payment.penalty_paid or 0)),
                'description': payment.loan_main_transaction.heading if payment.loan_main_transaction else 'Loan Payment'
            })
        
        return Response({
            'status': True,
            'data': {
                'loan_id': loan.id,
                'loan_number': loan.loan_number,
                'product_name': loan.loan_application_product.product_name,
                'status': loan.status,
                'loan_amount': float(loan.loan_amount),
                'disbursed_amount': float(disbursement.loan_amount) if disbursement else float(loan.loan_amount),
                'principal_balance': float(principal_balance),
                'interest_balance': float(interest_balance),
                'penalty_balance': float(penalty_paid or 0),
                'total_balance': float(total_balance),
                'principal_paid': float(princ_paid or 0),
                'interest_paid': float(int_paid or 0),
                'penalty_paid': float(penalty_paid or 0),
                'total_principal_expected': float(total_principal_expected or 0),
                'total_interest_expected': float(total_interest_expected or 0),
                'interest_rate': float(loan.int_rate),
                'interest_method': loan.int_method,
                'loan_period': loan.loan_period,
                'period_type': loan.period_type,
                'loan_date': loan.loan_date,
                'disbursement_date': disbursement_date,
                'loan_start_date': loan_start_date,
                'clear_off_date': loan.clear_off_date,
                'loan_officer': loan.loan_officer.name if loan.loan_officer else None,
                'next_payment': next_payment_data,
                'transactions': transactions_data
            }
        }, status=status.HTTP_200_OK)

class MobileSharesDetailView(APIView):
    """Get detailed shares info with last 10 transactions"""
    authentication_classes = []
    permission_classes = [AllowAny]
    
    def get(self, request, format=None):
        # Get customer_id from query params
        customer_id = request.query_params.get('customer_id')
        if not customer_id:
            return Response({
                'status': False,
                'message': 'customer_id is required'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            customer = Customer.objects.select_related(
                'customer_branch__branch_organisation'
            ).get(id=customer_id)
        except Customer.DoesNotExist:
            return Response({
                'status': False,
                'message': 'Customer not found'
            }, status=status.HTTP_404_NOT_FOUND)
        
        # Get shares balance using helper
        shares_info = get_client_shares_balance(customer)
        
        if not shares_info:
            return Response({
                'status': False,
                'message': 'No shares configuration found for this organization'
            }, status=status.HTTP_404_NOT_FOUND)
        
        # Get shares settings
        shares_settings = SharesSettings.objects.filter(
            organisation=customer.customer_branch.branch_organisation
        ).first()
        
        # Get shareholder info
        shareholder = ShareHolders.objects.filter(customer=customer).first()
        
        # Get last 10 shares transactions with details
        transactions = []
        if shareholder:
            share_transactions = SharesTransaction.objects.filter(
                shareholder=shareholder,
                deleted=False
            ).select_related(
                'system_transaction',
                'share_holder_trans_added_by__user_staff'
            ).order_by('-date_added')[:10]
            
            for trans in share_transactions:
                transactions.append({
                    'id': trans.id,
                    'date': trans.date_added.date(),
                    'transaction_type': trans.transaction_type,
                    'shares': float(trans.no_of_shares),
                    'share_value': float(trans.current_share_value),
                    'total_amount': float(trans.no_of_shares * trans.current_share_value),
                    'description': f'Shares {trans.transaction_type.title()}',
                    'added_by': trans.share_holder_trans_added_by.user_staff.name if trans.share_holder_trans_added_by and trans.share_holder_trans_added_by.user_staff else None,
                    'transaction_ref': trans.system_transaction.heading if trans.system_transaction else None
                })
        
        # Get recent dividends
        recent_dividends = []
        if shareholder:
            dividend_records = ShareDividendCustomers.objects.filter(
                customer=customer,
                status='shared'
            ).select_related('share_dividend').order_by('-date_added')[:5]
            
            for dividend in dividend_records:
                recent_dividends.append({
                    'id': dividend.id,
                    'date': dividend.date_added.date(),
                    'total_dividends': float(dividend.total_dividends),
                    'converted_to_savings': float(dividend.converted_to_savings),
                    'converted_to_shares': float(dividend.converted_to_shares),
                    'period': f"{dividend.share_dividend.start_date.date()} to {dividend.share_dividend.end_date.date()}"
                })
        
        # Calculate shares statistics
        total_shares_purchased = 0
        total_amount_invested = 0
        if shareholder:
            purchase_transactions = SharesTransaction.objects.filter(
                shareholder=shareholder,
                transaction_type__in=['purchase', 'transfer-in'],
                deleted=False
            ).aggregate(
                total_shares=Sum('no_of_shares'),
                total_value=Sum('current_share_value')
            )
            total_shares_purchased = purchase_transactions['total_shares'] or 0
            total_amount_invested = purchase_transactions['total_value'] or 0

        return Response({
            'status': True,
            'data': {
                'customer_id': customer.id,
                'customer_name': customer.name,
                'customer_number': customer.member_number,
                'is_shareholder': shareholder is not None,
                'shareholder_since': shareholder.date_added.date() if shareholder else None,
                
                # Current shares position
                'current_shares': float(shares_info.get('no_of_shares', 0)),
                'current_share_value': float(shares_info.get('share_value', 0)),
                'total_shares_value': float(shares_info.get('total_share_value', 0)),
                'withheld_shares': float(shares_info.get('all_total_no_of_shares', 0) - shares_info.get('no_of_shares', 0)),
                'withheld_value': float(shares_info.get('all_total_share_value', 0) - shares_info.get('total_share_value', 0)),
                
                # Investment summary
                'total_shares_purchased': float(total_shares_purchased),
                'total_amount_invested': float(total_amount_invested),
                'current_value': float(shares_info.get('total_share_value', 0)),
                'unrealized_gain_loss': float(shares_info.get('total_share_value', 0) - total_amount_invested),
                
                # Organization shares settings
                'organization_settings': {
                    'minimum_shares': shares_settings.minimum_shares if shares_settings else 0,
                    'current_share_value': shares_settings.share_value if shares_settings else 0,
                    'maximum_share_percent': shares_settings.maximum_share_percent if shares_settings else 0,
                    'share_capped_value': shares_settings.share_capped_value if shares_settings else 0
                } if shares_settings else None,
                
                # Transaction history
                'transactions': transactions,
                
                # Dividend history
                'recent_dividends': recent_dividends,
                
                # Summary stats
                'summary': {
                    'total_transactions': len(transactions),
                    'total_dividends_received': sum([d['total_dividends'] for d in recent_dividends]),
                    'last_transaction_date': transactions[0]['date'] if transactions else None,
                    'last_dividend_date': recent_dividends[0]['date'] if recent_dividends else None
                }
            }
        }, status=status.HTTP_200_OK)
