from rest_framework import serializers
from .models import (
    ExternalLoanProduct, ExternalLoanSector, ExternalLoanApplication,
    ExternalLoanApproval, ExternalLoanDisbursement, ExternalLoanWriteOff,
    ExternalLoanTransfer, ExternalLoanSettings, ExternalLoanGuarantors,
    ExternalLoanGuarantorsSecurity, ExternalLoanApplicationSecurity,
    ExternalLoanIncomeSource, ExternalLoanMainTransactions, ExternalLoanRecovery,
    ExternalLoanProductCharges, ExternalLoanRepaymentSchedule, ExternalLoanPaymentTransaction,
    ExternalLoanPayments, ExternalLoanPenalty, ExternalLoanPenaltyWaivered,
    ExternalLoanInterestWaivered, ExternalRescheduledLoans, ExternalLoanTopUp,
    ExternalLoanApplicationMember
)
from customers.serializers import CustomerSerializer
from users.serializers import StaffSerializer
from organisations.serializers import OrganisationBranchSerializer, OrganisationSerializer

class ExternalLoanProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanProduct
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by', 'organisation')

    def create(self, validated_data):
        # Organisation is set in the view's perform_create method
        return super().create(validated_data)

class ExternalLoanSectorSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanSector
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by', 'organisation')

    def create(self, validated_data):
        # Organisation is set in the view's perform_create method
        return super().create(validated_data)

class ExternalLoanApplicationMemberSerializer(serializers.ModelSerializer):
    customer_details = CustomerSerializer(source='customer', read_only=True)
    
    class Meta:
        model = ExternalLoanApplicationMember
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by', 'customer')

class ExternalLoanIncomeSourceSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanIncomeSource
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by', 'external_loan_application')

class ExternalLoanGuarantorsSerializer(serializers.ModelSerializer):
    guarantor_customer_details = CustomerSerializer(source='guarantor_customer', read_only=True)
    guarantor_organisation_details = OrganisationSerializer(source='guarantor_organisation', read_only=True)
    
    class Meta:
        model = ExternalLoanGuarantors
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanApplicationSecuritySerializer(serializers.ModelSerializer):
    def to_internal_value(self, data):
        if 'buying_date' in data and data['buying_date'] and len(str(data['buying_date'])) == 10:
            data = data.copy()
            data['buying_date'] = f"{data['buying_date']}T00:00:00Z"
        return super().to_internal_value(data)
    
    class Meta:
        model = ExternalLoanApplicationSecurity
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanApplicationSerializer(serializers.ModelSerializer):
    applicant_organisation_details = OrganisationSerializer(source='applicant_organisation', read_only=True)
    loan_provider_organisation_details = OrganisationSerializer(source='loan_provider_organisation', read_only=True)
    loan_officer_details = StaffSerializer(source='loan_officer', read_only=True)
    product_details = ExternalLoanProductSerializer(source='external_loan_product', read_only=True)
    sector_details = ExternalLoanSectorSerializer(source='external_loan_sector', read_only=True)
    branch_details = OrganisationBranchSerializer(source='organisation_branch', read_only=True)
    members = ExternalLoanApplicationMemberSerializer(many=True, read_only=True)
    income_sources = ExternalLoanIncomeSourceSerializer(many=True, read_only=True)
    guarantors = ExternalLoanGuarantorsSerializer(many=True, read_only=True)
    securities = ExternalLoanApplicationSecuritySerializer(many=True, read_only=True)
    
    # Add approval and disbursement data
    external_loan_approval = serializers.SerializerMethodField()
    external_loan_disbursement = serializers.SerializerMethodField()
    loan_balance = serializers.SerializerMethodField()
    loan_schedule_due_data = serializers.SerializerMethodField()
    loan_payment_history = serializers.SerializerMethodField()
    
    class Meta:
        model = ExternalLoanApplication
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by', 'loan_number', 'applicant_organisation')
    
    def get_external_loan_approval(self, obj):
        from .models import ExternalLoanApproval
        approval = ExternalLoanApproval.objects.filter(external_loan_application=obj).first()
        if approval:
            return {
                'id': approval.id,
                'date_added': approval.created_at,
                'last_updated': approval.updated_at,
                'approved_by': approval.approved_by.username if approval.approved_by else None,
                'approved_by_name': approval.approved_by.get_full_name() if approval.approved_by else None,
                'loan_amount': approval.approved_amount,
                'loan_period': approval.approved_duration,
                'int_rate': approval.approved_interest_rate,
                'approval_date': approval.approval_date,
                'approval_notes': approval.approval_notes,
                'approval_status': approval.approval_status,
                'external_loan_application': obj.id
            }
        return {}
    
    def get_external_loan_disbursement(self, obj):
        from .models import ExternalLoanDisbursement
        disbursement = ExternalLoanDisbursement.objects.filter(
            external_loan_application=obj,
            approval_status='approved'
        ).first()
        if disbursement:
            return {
                'id': disbursement.id,
                'date_added': disbursement.created_at,
                'last_updated': disbursement.updated_at,
                'disbursed_by': disbursement.disbursed_by.username if disbursement.disbursed_by else None,
                'disbursed_by_name': disbursement.disbursed_by.get_full_name() if disbursement.disbursed_by else None,
                'disbursed_amount': disbursement.disbursed_amount,
                'disbursement_method': disbursement.disbursement_method,
                'disbursement_date': disbursement.disbursement_date,
                'payment_reference': disbursement.payment_reference,
                'disbursement_notes': disbursement.disbursement_notes,
                'approval_status': disbursement.approval_status,
                'system_transaction': disbursement.system_transaction.id if disbursement.system_transaction else None,
                'external_loan_application': obj.id
            }
        return {}

    def get_loan_balance(self, obj):
        from .helper import get_external_loan_balance_detailed
        if obj.status in ['disbursed', 'cleared_off', 'written_off']:
            balance = get_external_loan_balance_detailed(obj.id)
            return {
                'principal_bal': balance['principal_balance'],
                'interest_bal': balance['interest_balance'],
                'penalty_bal': balance['penalty_balance'],
                'total': balance['total_balance'],
                'total_with_penalty': balance['total_balance'],
                'recovered_principal': 0
            }
        return {
            'principal_bal': 0,
            'interest_bal': 0,
            'penalty_bal': 0,
            'total': 0,
            'total_with_penalty': 0,
            'recovered_principal': 0
        }
    
    def get_loan_schedule_due_data(self, obj):
        from .models import ExternalLoanRepaymentSchedule
        from django.utils import timezone
        
        if obj.status not in ['disbursed', 'cleared_off', 'written_off']:
            return {'princ_due': 0, 'interest_due': 0, 'penalty_due': 0, 'total_due': 0, 'number_of_schedules': 0}
        
        # Get overdue schedules
        today = timezone.now().date()
        overdue_schedules = ExternalLoanRepaymentSchedule.objects.filter(
            external_loan_application=obj,
            status='active',
            expected_date__lt=today,
            is_fully_paid=False
        )
        
        total_princ_due = 0
        total_interest_due = 0
        total_penalty_due = 0
        number_of_schedules = overdue_schedules.count()
        
        for schedule in overdue_schedules:
            total_princ_due += (schedule.principal_expected - schedule.principal_paid)
            total_interest_due += (schedule.interest_expected - schedule.interest_paid)
            total_penalty_due += (schedule.penalty_amount - schedule.penalty_paid)
        
        return {
            'princ_due': round(total_princ_due, 2),
            'interest_due': round(total_interest_due, 2),
            'penalty_due': round(total_penalty_due, 2),
            'total_due': round(total_princ_due + total_interest_due + total_penalty_due, 2),
            'number_of_schedules': number_of_schedules
        }
    
    def get_loan_payment_history(self, obj):
        from .models import ExternalLoanPaymentTransaction, ExternalLoanPayments
        from django.db.models import Sum
        
        if obj.status not in ['disbursed', 'cleared_off', 'written_off']:
            return []
        
        payment_transactions = ExternalLoanPaymentTransaction.objects.filter(
            external_loan_application=obj,
            transaction_status='normal'
        ).order_by('-payment_date')[:10]
        
        payments_list = []
        for payment_txn in payment_transactions:
            payments = ExternalLoanPayments.objects.filter(
                external_loan_payment_transaction=payment_txn,
                payment_status='normal'
            ).aggregate(
                total_principal=Sum('princ_paid'),
                total_interest=Sum('int_paid'),
                total_penalty=Sum('penalty_paid')
            )
            
            payments_list.append({
                'id': payment_txn.id,
                'payment_date': payment_txn.payment_date,
                'amount': payment_txn.amount,
                'principal_paid': payments['total_principal'] or 0,
                'interest_paid': payments['total_interest'] or 0,
                'penalty_paid': payments['total_penalty'] or 0,
                'transaction_type': payment_txn.transaction_type,
                'added_by': payment_txn.added_by.username if payment_txn.added_by else ''
            })
        
        return payments_list

class ExternalLoanApplicationCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanApplication
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by', 'loan_number', 'applicant_organisation', 'organisation_branch')

class ExternalLoanApprovalSerializer(serializers.ModelSerializer):
    application_details = ExternalLoanApplicationSerializer(source='external_loan_application', read_only=True)
    approved_by_details = serializers.StringRelatedField(source='approved_by', read_only=True)
    
    class Meta:
        model = ExternalLoanApproval
        fields = '__all__'
        read_only_fields = ('created_at', 'updated_at', 'approved_by', 'approval_date')

class ExternalLoanApprovalCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanApproval
        fields = '__all__'
        read_only_fields = ('created_at', 'updated_at', 'approved_by', 'approval_date')

    def create(self, validated_data):
        validated_data['approved_by'] = self.context['request'].user
        return super().create(validated_data)

class ExternalLoanDisbursementSerializer(serializers.ModelSerializer):
    application_details = ExternalLoanApplicationSerializer(source='external_loan_application', read_only=True)
    disbursed_by_details = serializers.StringRelatedField(source='disbursed_by', read_only=True)
    approved_by_details = serializers.StringRelatedField(source='approved_by', read_only=True)
    source_account_details = serializers.StringRelatedField(source='source_account', read_only=True)
    
    class Meta:
        model = ExternalLoanDisbursement
        fields = '__all__'
        read_only_fields = ('created_at', 'updated_at', 'disbursed_by', 'disbursement_date')

class ExternalLoanDisbursementCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanDisbursement
        fields = '__all__'
        read_only_fields = ('created_at', 'updated_at', 'disbursed_by', 'disbursement_date', 'system_transaction')

    def create(self, validated_data):
        validated_data['disbursed_by'] = self.context['request'].user
        return super().create(validated_data)

class ExternalLoanWriteOffSerializer(serializers.ModelSerializer):
    application_details = ExternalLoanApplicationSerializer(source='external_loan_application', read_only=True)
    added_by_details = serializers.StringRelatedField(source='added_by', read_only=True)
    
    class Meta:
        model = ExternalLoanWriteOff
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanTransferSerializer(serializers.ModelSerializer):
    application_details = ExternalLoanApplicationSerializer(source='external_loan_application', read_only=True)
    from_officer_details = StaffSerializer(source='from_officer', read_only=True)
    to_officer_details = StaffSerializer(source='to_officer', read_only=True)
    transferred_by_details = serializers.StringRelatedField(source='transferred_by', read_only=True)
    
    class Meta:
        model = ExternalLoanTransfer
        fields = '__all__'
        read_only_fields = ('date_added', 'transferred_by')

class ExternalLoanSettingsSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanSettings
        fields = '__all__'
        read_only_fields = ('created_at', 'updated_at', 'created_by', 'updated_by')

class ExternalLoanGuarantorsSecuritySerializer(serializers.ModelSerializer):
    guarantor_details = ExternalLoanGuarantorsSerializer(source='external_loan_guarantor', read_only=True)
    
    class Meta:
        model = ExternalLoanGuarantorsSecurity
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanMainTransactionsSerializer(serializers.ModelSerializer):
    application_details = ExternalLoanApplicationSerializer(source='external_loan_application', read_only=True)
    added_by_details = serializers.StringRelatedField(source='added_by', read_only=True)
    
    class Meta:
        model = ExternalLoanMainTransactions
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanRecoverySerializer(serializers.ModelSerializer):
    application_details = ExternalLoanApplicationSerializer(source='external_loan_application', read_only=True)
    added_by_details = serializers.StringRelatedField(source='recovery_added_by', read_only=True)
    
    class Meta:
        model = ExternalLoanRecovery
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'recovery_added_by')

class ExternalLoanApplicationSearchSerializer(serializers.ModelSerializer):
    """Simplified serializer for search results"""
    applicant_organisation_name = serializers.CharField(source='applicant_organisation.name', read_only=True)
    loan_provider_organisation_name = serializers.CharField(source='loan_provider_organisation.name', read_only=True)
    
    class Meta:
        model = ExternalLoanApplication
        fields = ['id', 'loan_number', 'loan_amount', 'status', 'applicant_organisation_name', 'loan_provider_organisation_name', 'date_added']

class ExternalLoanProductChargesSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanProductCharges
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanRepaymentScheduleSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanRepaymentSchedule
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanPaymentTransactionSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanPaymentTransaction
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanPaymentsSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanPayments
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanPenaltySerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanPenalty
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanPenaltyWaiveredSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanPenaltyWaivered
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanInterestWaiveredSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanInterestWaivered
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalRescheduledLoansSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalRescheduledLoans
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanTopUpSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanTopUp
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')
    loan_provider_organisation_name = serializers.CharField(source='loan_provider_organisation.name', read_only=True)
    product_name = serializers.CharField(source='external_loan_product.product_name', read_only=True)
    
    class Meta:
        model = ExternalLoanApplication
        fields = ['id', 'loan_number', 'applicant_organisation_name', 'loan_provider_organisation_name', 'product_name', 'loan_amount', 'status', 'application_date']

# New serializers for additional models

class ExternalLoanProductChargesSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanProductCharges
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanRepaymentScheduleSerializer(serializers.ModelSerializer):
    remaining_principal = serializers.ReadOnlyField()
    remaining_interest = serializers.ReadOnlyField()
    remaining_penalty = serializers.ReadOnlyField()
    total_remaining = serializers.ReadOnlyField()
    payment_progress_percentage = serializers.ReadOnlyField()
    
    class Meta:
        model = ExternalLoanRepaymentSchedule
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by', 'is_fully_paid', 'is_overdue', 'days_overdue')

class ExternalLoanPaymentTransactionSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanPaymentTransaction
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanPaymentsSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanPayments
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanPenaltySerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanPenalty
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanPenaltyWaiveredSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanPenaltyWaivered
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanInterestWaiveredSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanInterestWaivered
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalRescheduledLoansSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalRescheduledLoans
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')

class ExternalLoanTopUpSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExternalLoanTopUp
        fields = '__all__'
        read_only_fields = ('date_added', 'last_updated', 'added_by')