from rest_framework import viewsets, status
from rest_framework.response import Response
from rest_framework.decorators import action
from .models import MobileMoneySettings
from .serializers import MobileMoneySettingsSerializer
from ledgers.models import OrganisationSubAccount
from organisations.models import Organisation
from users.models import UserSession
from organisations.models import OrganisationBranch
from decimal import Decimal
from customers.models import Customer
from savings.models import SavingAccount
from .mobile_money_helper import post_mobile_money_charge


def get_active_branch(request):
    auth_header = request.META.get("HTTP_AUTHORIZATION", "")
    token = auth_header.split(" ")[1] if " " in auth_header else None

    if not token:
        print("No token found")
        return None

    session = UserSession.objects.filter(user=request.user, session_token=token).first()
    if not session:
        print(f"No session for user {request.user} with token {token}")
        return None

    branch_id = session.data.get("organisation_branch_id")
    if not branch_id:
        print(f"No branch_id in session data for user {request.user}")
        return None

    try:
        branch = OrganisationBranch.objects.get(id=branch_id)
        return branch
    except OrganisationBranch.DoesNotExist:
        print(f"Branch {branch_id} does not exist")
        return None


class MobileMoneySettingsViewSet(viewsets.ModelViewSet):
    serializer_class = MobileMoneySettingsSerializer

    def get_queryset(self):
        branch = get_active_branch(self.request)
        if not branch:
            return MobileMoneySettings.objects.none()

        # Get organization like in the second code
        organization = branch.branch_organisation
        return MobileMoneySettings.objects.filter(organization=organization)

    def perform_create(self, serializer):
        branch = get_active_branch(self.request)
        if not branch:
            raise ValueError("No active branch in session")

        # Get organization like in the second code
        organization = branch.branch_organisation
        serializer.save(
            created_by=self.request.user,
            organization=organization
        )

    def perform_update(self, serializer):
        serializer.save()

    @action(detail=False, methods=['get'])
    def income_accounts(self, request):
        branch = get_active_branch(request)
        if not branch:
            return Response([], status=status.HTTP_200_OK)

        # Get organization like in the second code
        organization = branch.branch_organisation

        income_accounts = OrganisationSubAccount.objects.filter(
            organisation=organization,
            account_line='income'
        ).values('id', 'account_code', 'account_name')

        accounts_list = [
            {
                'id': acc['id'],
                'label': f"{acc['account_code']} - {acc['account_name']}",
                'value': acc['id']
            }
            for acc in income_accounts
        ]
        return Response(accounts_list)

    @action(detail=False, methods=['post'])
    def calculate_charge(self, request):
        branch = get_active_branch(request)
        if not branch:
            return Response(
                {'error': 'No active branch in session'},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Get organization like in the second code
        organization = branch.branch_organisation

        setting_type = request.data.get("setting_type")
        amount = Decimal(str(request.data.get("amount", 0)))

        if not setting_type:
            return Response({'error': 'Missing setting_type'}, status=status.HTTP_400_BAD_REQUEST)

        setting = MobileMoneySettings.objects.filter(
            organization=organization,
            setting_type=setting_type,
            is_active=True
        ).first()

        if not setting:
            return Response({
                'amount': float(amount),
                'charge': 0,
                'charge_type': None,
                'net_amount': float(amount)
            })

        charge = setting.calculate_charge(amount)
        net_amount = amount - charge

        return Response({
            'amount': float(amount),
            'charge': float(charge),
            'charge_type': setting.charge_type,
            'net_amount': float(net_amount)
        })

    @action(detail=False, methods=['post'])
    def process_transaction(self, request):
        branch = get_active_branch(request)
        if not branch:
            return Response(
                {'error': 'No active branch in session'},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Get organization like in the second code
        organization = branch.branch_organisation

        try:
            member_id = request.data.get('member_id')
            saving_account_id = request.data.get('saving_account_id')
            amount = Decimal(str(request.data.get("amount")))
            transaction_type = request.data.get("transaction_type")  # deposit / withdrawal

            if not all([member_id, saving_account_id, amount, transaction_type]):
                return Response(
                    {'error': 'Missing required fields'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            member = Customer.objects.get(id=member_id)
            customer_account = SavingAccount.objects.get(id=saving_account_id)

            charge_result = post_mobile_money_charge(
                member=member,
                amount=amount,
                transaction_type=transaction_type,
                organization=organization,
                customer_account=customer_account,
                created_by=request.user
            )

            return Response(charge_result, status=status.HTTP_201_CREATED)

        except Customer.DoesNotExist:
            return Response({'error': 'Customer not found'}, status=status.HTTP_404_NOT_FOUND)
        except SavingAccount.DoesNotExist:
            return Response({'error': 'Saving account not found'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)
