# budgets/serializers.py
from rest_framework import serializers
from .models import Budget, BudgetRow, BudgetCell
from datetime import datetime
from ledgers.models import OrganisationSubAccount

class BudgetCellSerializer(serializers.ModelSerializer):
    class Meta:
        model = BudgetCell
        fields = ['month', 'value']


class BudgetRowSerializer(serializers.ModelSerializer):
    cells = BudgetCellSerializer(many=True)

    class Meta:
        model = BudgetRow
        fields = ['id', 'account_code', 'account_name', 'row_type', 'cells']

    def create(self, validated_data):
        cells_data = validated_data.pop('cells', [])
        row = BudgetRow.objects.create(**validated_data)
        for cell_data in cells_data:
            BudgetCell.objects.create(row=row, **cell_data)
        return row

    def update(self, instance, validated_data):
        cells_data = validated_data.pop('cells', [])
        instance.account_code = validated_data.get('account_code', instance.account_code)
        instance.account_name = validated_data.get('account_name', instance.account_name)
        instance.row_type = validated_data.get('row_type', instance.row_type)
        instance.save()

        # Update or create cells
        for cell_data in cells_data:
            cell, created = BudgetCell.objects.update_or_create(
                row=instance,
                month=cell_data['month'],
                defaults={'value': cell_data['value']}
            )
        return instance


class BudgetSerializer(serializers.ModelSerializer):
    rows = BudgetRowSerializer(many=True)
    total_income = serializers.SerializerMethodField()
    total_expenses = serializers.SerializerMethodField()
    budget_number = serializers.SerializerMethodField()

    class Meta:
        model = Budget
        fields = ['id', 'financial_year', 'start_date', 'budget_period', 'usage_check', 'status', 'branch', 'rows', 'total_income', 'total_expenses', 'budget_number']

    def get_total_income(self, obj):
        total = sum(
            cell.value
            for row in obj.rows.filter(row_type='income')
            for cell in row.cells.all()
        )
        return round(total, 2)

    def get_total_expenses(self, obj):
        total = sum(
            cell.value
            for row in obj.rows.filter(row_type='expense')
            for cell in row.cells.all()
        )
        return round(total, 2)

    def get_budget_number(self, obj):
        position = Budget.objects.filter(
            branch=obj.branch,
            id__lte=obj.id
        ).count()
        return f"BDG-{position:04d}"

    def create(self, validated_data):
        rows_data = validated_data.pop('rows', [])
        budget = Budget.objects.create(**validated_data)
        for row_data in rows_data:
            row_data['budget'] = budget
            BudgetRowSerializer().create(row_data)
        return budget

    def update(self, instance, validated_data):
        rows_data = validated_data.pop('rows', [])
        instance.financial_year = validated_data.get('financial_year', instance.financial_year)
        instance.start_date = validated_data.get('start_date', instance.start_date)
        instance.budget_period = validated_data.get('budget_period', instance.budget_period)
        instance.usage_check = validated_data.get('usage_check', instance.usage_check)
        instance.status = validated_data.get('status', instance.status)
        instance.save()

        for row_data in rows_data:
            row_id = row_data.get('id')
            if row_id:
                row = BudgetRow.objects.get(id=row_id, budget=instance)
                BudgetRowSerializer().update(row, row_data)
            else:
                row_data['budget'] = instance
                BudgetRowSerializer().create(row_data)
        return instance
    
class BudgetAccountSerializer(serializers.ModelSerializer):
    """
    Simplified serializer for budgeting that returns ALL accounts
    in the hierarchy regardless of transactions.
    """
    child_accounts = serializers.SerializerMethodField(read_only=True)
    has_children = serializers.SerializerMethodField(read_only=True)
    full_path = serializers.SerializerMethodField(read_only=True)
    
    class Meta:
        model = OrganisationSubAccount
        fields = [
            'id',
            'account_name',
            'account_code',
            'account_line',
            'parent_id',
            'has_children',
            'child_accounts',
            'full_path',
            'allow_sub_accounts'
        ]

    def get_has_children(self, obj):
        """Check if this account has any child accounts"""
        return OrganisationSubAccount.objects.filter(
            parent_id=obj.id,
            deleted=False
        ).exists()

    def get_child_accounts(self, obj):
        """
        Recursively get ALL child accounts regardless of transactions.
        This ensures the complete hierarchy is returned for budgeting.
        """
        children = OrganisationSubAccount.objects.filter(
            parent_id=obj.id,
            deleted=False
        ).order_by('account_code')
        
        # Recursively serialize children
        serializer = BudgetAccountSerializer(
            instance=children,
            many=True,
            context=self.context
        )
        return serializer.data

    def get_full_path(self, obj):
        """
        Get the full path of the account (e.g., 'Parent > Child > Sub-child')
        Useful for display purposes in the budget form.
        """
        path = [obj.account_name]
        current = obj
        
        # Traverse up the hierarchy
        while current.parent_id:
            current = current.parent_id
            path.insert(0, current.account_name)
        
        return ' > '.join(path)


class BudgetAccountStructureSerializer(serializers.Serializer):
    """
    Serializer that returns accounts grouped by account_line (income/expenses)
    in a structure optimized for budget creation.
    """
    income = serializers.SerializerMethodField()
    expenses = serializers.SerializerMethodField()
    
    def get_income(self, obj):
        """Get all income accounts"""
        organisation_id = self.context.get('organisation_id')
        
        # Get top-level income accounts
        income_accounts = OrganisationSubAccount.objects.filter(
            account_line='income',
            account_organisation_id=organisation_id,
            parent_id__isnull=True,
            deleted=False
        ).order_by('account_code')
        
        return BudgetAccountSerializer(
            income_accounts,
            many=True,
            context=self.context
        ).data
    
    def get_expenses(self, obj):
        """Get all expense accounts"""
        organisation_id = self.context.get('organisation_id')
        
        # Get top-level expense accounts
        expense_accounts = OrganisationSubAccount.objects.filter(
            account_line='expenses',
            account_organisation_id=organisation_id,
            parent_id__isnull=True,
            deleted=False
        ).order_by('account_code')
        
        return BudgetAccountSerializer(
            expense_accounts,
            many=True,
            context=self.context
        ).data    
