"""资金池：划额度、派单扣减、退款释放。"""
from decimal import Decimal

from django.db import transaction
from django.db.models import F

from merchant_ops.constants import (
    WALLET_ALLOCATE, WALLET_DISPATCH_CONFIRM, WALLET_REFUND_RELEASE, WALLET_REVOKE,
)
from merchant_ops.models import MerchantStaffWallet, MerchantStaffWalletLedger
from users.models import UserShangjia


def get_or_create_wallet(member):
    wallet, _ = MerchantStaffWallet.objects.get_or_create(
        merchant_id=member.merchant_id,
        staff_user_id=member.staff_user_id,
        defaults={'member': member},
    )
    return wallet


def allocate_quota(member, amount, operator_id, remark=''):
    """
    老板划额度：从商家余额转入客服可用额度（商家余额减少，客服 quota_total 增加）。
    """
    amount = Decimal(str(amount))
    if amount <= 0:
        raise ValueError('划额度必须大于0')

    with transaction.atomic():
        shangjia = UserShangjia.objects.select_for_update().get(user__UserUID=member.merchant_id)
        if amount > shangjia.yue:
            raise ValueError(f'商家余额不足，当前{shangjia.yue}元')

        wallet = MerchantStaffWallet.objects.select_for_update().get(
            merchant_id=member.merchant_id,
            staff_user_id=member.staff_user_id,
        )
        UserShangjia.objects.filter(id=shangjia.id).update(yue=F('yue') - amount)
        wallet.quota_total = F('quota_total') + amount
        wallet.save(update_fields=['quota_total'])
        wallet.refresh_from_db()
        MerchantStaffWalletLedger.objects.create(
            wallet=wallet,
            merchant_id=member.merchant_id,
            staff_user_id=member.staff_user_id,
            change_type=WALLET_ALLOCATE,
            amount=amount,
            balance_after=wallet.quota_available,
            operator_id=operator_id,
            remark=remark or '老板划额度',
        )
    return wallet


def check_wallet_available(member, amount):
    amount = Decimal(str(amount))
    wallet = get_or_create_wallet(member)
    if amount > wallet.quota_available:
        raise ValueError(f'客服可用额度不足，当前{wallet.quota_available}元')


def confirm_dispatch_deduct(member, amount, order_id, operator_id):
    """派单成功：仅扣客服额度（商家余额已在划额度时扣除）。"""
    amount = Decimal(str(amount))
    with transaction.atomic():
        wallet = MerchantStaffWallet.objects.select_for_update().get(
            merchant_id=member.merchant_id,
            staff_user_id=member.staff_user_id,
        )
        available = wallet.quota_total - wallet.quota_used - wallet.quota_frozen
        if amount > available:
            raise ValueError('客服可用额度不足')
        wallet.quota_used = F('quota_used') + amount
        wallet.save(update_fields=['quota_used'])
        wallet.refresh_from_db()
        MerchantStaffWalletLedger.objects.create(
            wallet=wallet,
            merchant_id=member.merchant_id,
            staff_user_id=member.staff_user_id,
            change_type=WALLET_DISPATCH_CONFIRM,
            amount=-amount,
            balance_after=wallet.quota_available,
            related_order_id=order_id,
            operator_id=operator_id,
            remark='派单扣额度',
        )


def release_dispatch_quota(order_id, amount, operator_id, remark='退款释放额度'):
    """订单撤销/退款：释放子客服已扣额度。"""
    from merchant_ops.models import MerchantOrderDispatch, MerchantStaffMember

    amount = Decimal(str(amount))
    if amount <= 0 or not order_id:
        return

    disp = MerchantOrderDispatch.objects.filter(order_id=order_id).first()
    if not disp or not disp.staff_member_id:
        return

    member = MerchantStaffMember.objects.filter(id=disp.staff_member_id).first()
    if not member:
        return

    with transaction.atomic():
        wallet = MerchantStaffWallet.objects.select_for_update().filter(
            merchant_id=member.merchant_id,
            staff_user_id=member.staff_user_id,
        ).first()
        if not wallet:
            return
        release = min(amount, wallet.quota_used)
        if release <= 0:
            return
        wallet.quota_used = F('quota_used') - release
        wallet.save(update_fields=['quota_used'])
        wallet.refresh_from_db()
        MerchantStaffWalletLedger.objects.create(
            wallet=wallet,
            merchant_id=member.merchant_id,
            staff_user_id=member.staff_user_id,
            change_type=WALLET_REFUND_RELEASE,
            amount=release,
            balance_after=wallet.quota_available,
            related_order_id=order_id,
            operator_id=operator_id or member.staff_user_id,
            remark=remark,
        )


def is_staff_quota_order(order_id):
    """订单是否由子客服额度出资（划额度池 + 派单扣额度，非老板余额直扣）。"""
    from merchant_ops.models import MerchantOrderDispatch

    if not order_id:
        return False
    return MerchantOrderDispatch.objects.filter(
        order_id=order_id,
        staff_member_id__isnull=False,
    ).exists()


def revoke_quota(member, amount, operator_id, remark=''):
    """
    收回未使用额度：客服 quota_total 减少，商家余额增加。
    已派单占用（quota_used）部分不可收回，防止资金悬空或重复退回。
    """
    amount = Decimal(str(amount))
    if amount <= 0:
        raise ValueError('收回额度必须大于0')

    with transaction.atomic():
        wallet = MerchantStaffWallet.objects.select_for_update().get(
            merchant_id=member.merchant_id,
            staff_user_id=member.staff_user_id,
        )
        available = wallet.quota_total - wallet.quota_used - wallet.quota_frozen
        if amount > available:
            raise ValueError(
                f'最多可收回{available}元（未使用额度）；'
                f'已派单占用{wallet.quota_used}元需先撤销/退款订单后再释放'
            )

        shangjia = UserShangjia.objects.select_for_update().get(user__UserUID=member.merchant_id)
        wallet.quota_total = F('quota_total') - amount
        wallet.save(update_fields=['quota_total'])
        wallet.refresh_from_db()
        UserShangjia.objects.filter(id=shangjia.id).update(yue=F('yue') + amount)

        MerchantStaffWalletLedger.objects.create(
            wallet=wallet,
            merchant_id=member.merchant_id,
            staff_user_id=member.staff_user_id,
            change_type=WALLET_REVOKE,
            amount=-amount,
            balance_after=wallet.quota_available,
            operator_id=operator_id,
            remark=remark or '收回未使用额度',
        )
    return wallet
