from django.db import transaction
from django.utils import timezone
from django.db.models import Q
from ledgers.models import SystemTransactions, InterBranchTransactions
from loans.models import (
    LoanApplication,
    LoanApplicationDisbursement,
    LoanMainTransactions,
    LoanPaymentTransaction,
    LoanPayments,
    LoanRepaymentSchedule,
    LoanPenalty,
    RescheduledLoans,
    LoanApplicationWithHold,
    LoanGuarantors,
    LoanApplicationSecurity,
    LoanApplicationApproval,
    LoanIncomeSource,
    LoanPenaltyWaivered,
    LoanInterestWaivered,
    LoanWrittenOff,
    LoanRecovery,
)
from savings.models import (
    SavingAccountTransactions,
    GroupSavingTransaction,
    PendingWithdrawals,
    TransferTransactions,
    FixedDeposit,
    FixedDepositSchedule,
    InterestPaymentTransaction,
    AccountBookings,
    AccountBookingPayments,
    SchoolFeesPaymentTransactions,
    BulkSavingsChargesTransactions,
)
from shares.models import SharesTransaction
from overdraft.models import OverDrafts, OverDraftPayment
from ledgers.models import (
    CashTransfers,
    CreditorSupplies,
    CreditorPayments,
    DebtorSupplies,
    DebtorPayments,
)
import logging
from users.audit_log_helper import add_system_audit_trail

logger = logging.getLogger(__name__)


def _deletion_fields(user_id, now):
    """Return the common deletion fields dict for .update() calls."""
    return {"deleted": True, "deleted_by_id": user_id, "deleted_at": now}


def _log_deletion(action, message, user_id, branch):
    """Fire an audit trail entry for a deletion. Silently skips if user or branch is missing."""
    try:
        if user_id and branch:
            from users.models import User
            user = User.objects.filter(pk=user_id).first()
            if user:
                add_system_audit_trail('transaction_management', action, message, '', {}, {}, user, branch)
    except Exception as e:
        logger.warning(f"Audit trail failed for action '{action}': {e}")


def soft_delete_transaction_by_reference(reference_number, branch_id, user_id=None, branch=None):
    """
    Soft delete a transaction and all its related records based on reference number.

    Args:
        reference_number (str): The reference number of the transaction to delete
        branch_id (int): The branch ID from frontend
        user_id (int): The ID of the user performing the deletion

    Returns:
        dict: Result containing success status and message
    """
    now = timezone.now()

    try:
        with transaction.atomic():
            system_transaction = SystemTransactions.objects.filter(
                reference_no=reference_number, branch_id=branch_id, deleted=False
            ).first()

            if system_transaction and not branch:
                branch = system_transaction.branch

            if not system_transaction:
                return {
                    "success": False,
                    "message": f"Transaction with reference number {reference_number} not found or already deleted",
                }

            inter_branch_record = InterBranchTransactions.objects.filter(
                Q(source_transaction=system_transaction)
                | Q(destination_transaction=system_transaction),
                deleted=False,
            ).first()

            if inter_branch_record:
                source_trans = inter_branch_record.source_transaction
                dest_trans = inter_branch_record.destination_transaction

                transaction_types = _determine_transaction_types(reference_number)

                for transaction_type in transaction_types:
                    if transaction_type == "loan":
                        _soft_delete_loan_transaction_interbranch(
                            source_trans, dest_trans, reference_number, user_id, now
                        )
                    elif transaction_type == "savings":
                        _soft_delete_savings_transaction_interbranch(
                            source_trans, dest_trans, reference_number, user_id, now
                        )
                    elif transaction_type == "shares":
                        _soft_delete_shares_transaction_interbranch(
                            source_trans, dest_trans, reference_number, user_id, now
                        )
                    elif transaction_type == "fixed_deposit":
                        _soft_delete_fixed_deposit_transaction_interbranch(
                            source_trans, dest_trans, reference_number, user_id, now
                        )
                    elif transaction_type == "interest_payment":
                        _soft_delete_interest_payment_transaction_interbranch(
                            source_trans, dest_trans, reference_number, user_id, now
                        )
                    elif transaction_type == "expense":
                        pass
                    elif transaction_type == "general":
                        _soft_delete_general_transaction_interbranch(
                            source_trans, dest_trans, reference_number, user_id, now
                        )

                source_trans.deleted = True
                source_trans.deleted_by_id = user_id
                source_trans.deleted_at = now
                source_trans.save()

                dest_trans.deleted = True
                dest_trans.deleted_by_id = user_id
                dest_trans.deleted_at = now
                dest_trans.save()

                inter_branch_record.deleted = True
                inter_branch_record.deleted_by_id = user_id
                inter_branch_record.deleted_at = now
                inter_branch_record.save()

                _log_deletion(
                    'delete_transaction',
                    f'Deleted inter-branch transaction {reference_number}: {source_trans.heading}',
                    user_id, branch
                )
                logger.info(f"Successfully soft deleted inter-branch transaction {reference_number}")

            else:
                transaction_types = _determine_transaction_types(reference_number)

                result = {"success": True, "message": "Transaction processed successfully"}
                for transaction_type in transaction_types:
                    if transaction_type == "loan":
                        result = _soft_delete_loan_transaction(
                            system_transaction, reference_number, user_id, now
                        )
                    elif transaction_type == "savings":
                        result = _soft_delete_savings_transaction(
                            system_transaction, reference_number, user_id, now
                        )
                    elif transaction_type == "shares":
                        result = _soft_delete_shares_transaction(
                            system_transaction, reference_number, user_id, now
                        )
                    elif transaction_type == "fixed_deposit":
                        result = _soft_delete_fixed_deposit_transaction(
                            system_transaction, reference_number, user_id, now
                        )
                    elif transaction_type == "interest_payment":
                        result = _soft_delete_interest_payment_transaction(
                            system_transaction, reference_number, user_id, now
                        )
                    elif transaction_type == "expense":
                        result = _soft_delete_expense_transaction(
                            system_transaction, reference_number, user_id, now
                        )
                    elif transaction_type == "general":
                        result = _soft_delete_general_transaction(
                            system_transaction, reference_number, user_id, now
                        )

                    if not result["success"]:
                        return result

                system_transaction.deleted = True
                system_transaction.deleted_by_id = user_id
                system_transaction.deleted_at = now
                system_transaction.save()

                _log_deletion(
                    'delete_transaction',
                    f'Deleted transaction {reference_number}: {system_transaction.heading}',
                    user_id, branch
                )
                logger.info(f"Successfully soft deleted transaction {reference_number}")

            return {"success": True, "message": "Transaction soft deleted successfully"}

    except Exception as e:
        logger.error(f"Error soft deleting transaction {reference_number}: {str(e)}")
        return {
            "success": False,
            "message": f"Error occurred while deleting transaction: {str(e)}",
        }


def _determine_transaction_types(reference_number):
    """Determine transaction types based on reference number pattern - returns list of types"""
    ref_lower = reference_number.lower()
    types = []

    if "exp-" in ref_lower:
        types.append("expense")
        return types

    if any(pattern in ref_lower for pattern in ["ln-in-", "ln-int-", "ln-p-", "ln-d-"]):
        types.append("loan")

    if any(
        pattern in ref_lower
        for pattern in [
            "dep-", "dvsa-", "fx-d-", "fx-d-p-", "fx-py-", "fx-py-t-",
            "inc-", "int-py-", "int-py-t-", "lbt-", "ln-d-", "ln-p-",
            "ln-in-", "ln-int-", "mm-dep-", "mm-wit-", "wd-", "salary-",
            "sav-tr-", "sbt", "p-sh-", "w-sh-", "t-sh-",
        ]
    ):
        types.append("savings")

    if any(pattern in ref_lower for pattern in ["p-sh-", "w-sh-", "t-sh-", "dvsa-"]):
        types.append("shares")

    if any(pattern in ref_lower for pattern in ["fx-d-", "fx-d-p-", "fx-py-", "fx-py-t-"]):
        types.append("fixed_deposit")

    if any(pattern in ref_lower for pattern in ["int-py-", "int-py-t-"]):
        types.append("interest_payment")

    return types if types else ["general"]


def _soft_delete_loan_transaction(system_transaction, reference_number, user_id, now):
    """Soft delete loan-related transactions"""
    try:
        ref_lower = reference_number.lower()
        df = _deletion_fields(user_id, now)

        loan_main_trans = LoanMainTransactions.objects.filter(
            system_transaction=system_transaction
        ).first()

        if loan_main_trans:
            loan_main_trans.deleted = True
            loan_main_trans.deleted_by_id = user_id
            loan_main_trans.deleted_at = now
            loan_main_trans.save()

            if "ln-p-" in ref_lower and loan_main_trans.loan_application:
                _soft_delete_loan_payment_records(
                    loan_application=loan_main_trans.loan_application,
                    system_transaction=system_transaction,
                    user_id=user_id,
                    now=now,
                )

            if "ln-d-" in ref_lower:
                loan_application = loan_main_trans.loan_application
                if loan_application:
                    _soft_delete_all_loan_records(loan_application, user_id, now)
        else:
            loan_disbursement = LoanApplicationDisbursement.objects.filter(
                system_transaction=system_transaction
            ).first()

            if loan_disbursement and "ln-d-" in ref_lower:
                loan_application = loan_disbursement.loan_application
                if loan_application:
                    _soft_delete_all_loan_records(loan_application, user_id, now)

        return {"success": True, "message": "Loan transaction soft deleted successfully"}

    except Exception as e:
        logger.error(f"Error deleting loan transaction: {str(e)}")
        return {"success": False, "message": f"Error deleting loan transaction: {str(e)}"}


def _soft_delete_all_loan_records(loan_application, user_id, now):
    """Soft delete all records related to a loan application"""
    df = _deletion_fields(user_id, now)

    loan_system_transactions = SystemTransactions.objects.filter(
        Q(main_loan_transaction__loan_application=loan_application)
        | Q(main_system_transaction__loan_application=loan_application)
    )

    SavingAccountTransactions.objects.filter(
        transaction__in=loan_system_transactions
    ).update(**df)

    LoanPayments.objects.filter(loan_application=loan_application).update(**df)
    LoanPaymentTransaction.objects.filter(loan_application=loan_application).update(**df)
    LoanMainTransactions.objects.filter(loan_application=loan_application).update(**df)
    LoanRepaymentSchedule.objects.filter(loan_application=loan_application).update(**df)
    LoanPenalty.objects.filter(loan_application=loan_application).update(**df)
    RescheduledLoans.objects.filter(loan_application=loan_application).update(**df)
    LoanApplicationWithHold.objects.filter(loan_application=loan_application).update(**df)
    LoanGuarantors.objects.filter(loan_application=loan_application).update(**df)
    LoanApplicationSecurity.objects.filter(loan_application=loan_application).update(**df)
    LoanApplicationApproval.objects.filter(loan_application=loan_application).update(**df)
    LoanIncomeSource.objects.filter(loan_application=loan_application).update(**df)
    LoanPenaltyWaivered.objects.filter(loan_application=loan_application).update(**df)
    LoanInterestWaivered.objects.filter(loan_application=loan_application).update(**df)
    LoanWrittenOff.objects.filter(loan_application=loan_application).update(**df)
    LoanRecovery.objects.filter(loan_application=loan_application).update(**df)
    LoanApplicationDisbursement.objects.filter(loan_application=loan_application).update(**df)

    loan_application.deleted = True
    loan_application.deleted_by_id = user_id
    loan_application.deleted_at = now
    loan_application.save()


def _soft_delete_loan_payment_records(loan_application, user_id, now, system_transaction=None):
    """Soft delete records related to a loan payment"""
    df = _deletion_fields(user_id, now)

    LoanPayments.objects.filter(loan_application=loan_application).update(**df)
    LoanPaymentTransaction.objects.filter(loan_application=loan_application).update(**df)

    if system_transaction:
        SavingAccountTransactions.objects.filter(transaction=system_transaction).update(**df)


def _soft_delete_savings_transaction(system_transaction, reference_number, user_id, now):
    """Soft delete savings-related transactions"""
    try:
        df = _deletion_fields(user_id, now)

        SavingAccountTransactions.objects.filter(transaction=system_transaction).update(**df)

        saving_trans = SavingAccountTransactions.objects.filter(
            transaction=system_transaction
        ).first()

        if saving_trans:
            GroupSavingTransaction.objects.filter(savings=saving_trans).update(**df)

        PendingWithdrawals.objects.filter(
            saving_account_transaction__transaction=system_transaction
        ).update(**df)

        TransferTransactions.objects.filter(
            Q(sender_transaction__transaction=system_transaction)
            | Q(reciever_transaction__transaction=system_transaction)
        ).update(**df)

        return {"success": True, "message": "Savings transaction soft deleted successfully"}

    except Exception as e:
        return {"success": False, "message": f"Error deleting savings transaction: {str(e)}"}


def _soft_delete_shares_transaction(system_transaction, reference_number, user_id, now):
    """Soft delete shares-related transactions"""
    try:
        df = _deletion_fields(user_id, now)
        SharesTransaction.objects.filter(system_transaction=system_transaction).update(**df)
        return {"success": True, "message": "Shares transaction soft deleted successfully"}

    except Exception as e:
        return {"success": False, "message": f"Error deleting shares transaction: {str(e)}"}


def _soft_delete_overdraft_transaction(system_transaction, reference_number, user_id, now):
    """Soft delete overdraft-related transactions"""
    try:
        df = _deletion_fields(user_id, now)
        OverDrafts.objects.filter(reference_transaction=system_transaction).update(**df)
        OverDraftPayment.objects.filter(transaction=system_transaction).update(**df)
        return {"success": True, "message": "Overdraft transaction soft deleted successfully"}

    except Exception as e:
        return {"success": False, "message": f"Error deleting overdraft transaction: {str(e)}"}


def _soft_delete_fixed_deposit_transaction(system_transaction, reference_number, user_id, now):
    """Soft delete fixed deposit-related transactions"""
    try:
        df = _deletion_fields(user_id, now)

        FixedDeposit.objects.filter(reference_transaction=system_transaction).update(**df)

        fixed_deposit = FixedDeposit.objects.filter(
            reference_transaction=system_transaction
        ).first()

        if fixed_deposit:
            FixedDepositSchedule.objects.filter(fixed_deposit=fixed_deposit).update(**df)

        return {"success": True, "message": "Fixed deposit transaction soft deleted successfully"}

    except Exception as e:
        return {"success": False, "message": f"Error deleting fixed deposit transaction: {str(e)}"}


def _soft_delete_general_transaction(system_transaction, reference_number, user_id, now):
    """Soft delete general transactions"""
    try:
        df = _deletion_fields(user_id, now)

        CashTransfers.objects.filter(reference_transaction=system_transaction).update(**df)
        CreditorSupplies.objects.filter(reference_transaction=system_transaction).update(**df)
        CreditorPayments.objects.filter(reference_transaction=system_transaction).update(**df)
        DebtorSupplies.objects.filter(reference_transaction=system_transaction).update(**df)
        DebtorPayments.objects.filter(reference_transaction=system_transaction).update(**df)
        AccountBookings.objects.filter(
            account__customer_account__transaction=system_transaction, deleted=False
        ).update(**df)
        AccountBookingPayments.objects.filter(
            reference_transaction=system_transaction
        ).update(**df)
        SchoolFeesPaymentTransactions.objects.filter(
            system_transaction=system_transaction
        ).update(**df)

        return {"success": True, "message": "General transaction soft deleted successfully"}

    except Exception as e:
        return {"success": False, "message": f"Error deleting general transaction: {str(e)}"}


def _soft_delete_loan_transaction_interbranch(
    source_trans, dest_trans, reference_number, user_id, now
):
    """Handle loan transaction deletion for inter-branch transactions"""
    ref_lower = reference_number.lower()

    for trans in [source_trans, dest_trans]:
        loan_main = LoanMainTransactions.objects.filter(system_transaction=trans).first()
        if loan_main:
            loan_main.deleted = True
            loan_main.deleted_by_id = user_id
            loan_main.deleted_at = now
            loan_main.save()

            if "ln-p-" in ref_lower and loan_main.loan_application:
                _soft_delete_loan_payment_records(
                    loan_application=loan_main.loan_application,
                    system_transaction=trans,
                    user_id=user_id,
                    now=now,
                )

            if "ln-d-" in ref_lower and loan_main.loan_application:
                _soft_delete_all_loan_records(loan_main.loan_application, user_id, now)


def _soft_delete_savings_transaction_interbranch(
    source_trans, dest_trans, reference_number, user_id, now
):
    """Handle savings transaction deletion for inter-branch transactions"""
    df = _deletion_fields(user_id, now)
    for trans in [source_trans, dest_trans]:
        SavingAccountTransactions.objects.filter(transaction=trans).update(**df)


def _soft_delete_shares_transaction_interbranch(
    source_trans, dest_trans, reference_number, user_id, now
):
    """Handle shares transaction deletion for inter-branch transactions"""
    df = _deletion_fields(user_id, now)
    for trans in [source_trans, dest_trans]:
        SharesTransaction.objects.filter(system_transaction=trans).update(**df)


def _soft_delete_fixed_deposit_transaction_interbranch(
    source_trans, dest_trans, reference_number, user_id, now
):
    """Handle fixed deposit transaction deletion for inter-branch transactions"""
    df = _deletion_fields(user_id, now)
    for trans in [source_trans, dest_trans]:
        FixedDeposit.objects.filter(reference_transaction=trans).update(**df)


def _soft_delete_general_transaction_interbranch(
    source_trans, dest_trans, reference_number, user_id, now
):
    """Handle general transaction deletion for inter-branch transactions"""
    df = _deletion_fields(user_id, now)
    for trans in [source_trans, dest_trans]:
        CashTransfers.objects.filter(reference_transaction=trans).update(**df)


def _soft_delete_interest_payment_transaction(system_transaction, reference_number, user_id, now):
    """Soft delete interest payment transactions"""
    try:
        df = _deletion_fields(user_id, now)

        saving_transactions = SavingAccountTransactions.objects.filter(
            transaction=system_transaction
        )

        for saving_trans in saving_transactions:
            InterestPaymentTransaction.objects.filter(savings=saving_trans).update(**df)

        saving_transactions.update(**df)

        return {
            "success": True,
            "message": "Interest payment transaction soft deleted successfully",
        }

    except Exception as e:
        return {
            "success": False,
            "message": f"Error deleting interest payment transaction: {str(e)}",
        }


def _soft_delete_interest_payment_transaction_interbranch(
    source_trans, dest_trans, reference_number, user_id, now
):
    """Handle interest payment transaction deletion for inter-branch transactions"""
    df = _deletion_fields(user_id, now)
    for trans in [source_trans, dest_trans]:
        saving_transactions = SavingAccountTransactions.objects.filter(transaction=trans)
        for saving_trans in saving_transactions:
            InterestPaymentTransaction.objects.filter(savings=saving_trans).update(**df)
        saving_transactions.update(**df)


def _soft_delete_expense_transaction(system_transaction, reference_number, user_id, now):
    """Soft delete expense transactions - only deletes from SystemTransactions table"""
    try:
        SystemTransactions.objects.filter(pk=system_transaction.pk).update(
            **_deletion_fields(user_id, now)
        )
        return {"success": True, "message": "Expense transaction soft deleted successfully"}

    except Exception as e:
        return {"success": False, "message": f"Error deleting expense transaction: {str(e)}"}
