"""子客服日统计 + 商家日统计双写。"""
import logging
from datetime import date
from decimal import Decimal

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

from backend.utils import update_shangjia_daily
from merchant_ops.constants import STAT_ACTION_DISPATCH, STAT_ACTION_REFUND, STAT_ACTION_SETTLE
from merchant_ops.models import MerchantOrderDispatch, MerchantStaffDailyStats, MerchantStaffMember
from merchant_ops.services.wallet import release_dispatch_quota

logger = logging.getLogger(__name__)


def _action_fields(action, amount):
    amount = Decimal(str(amount))
    if action == STAT_ACTION_DISPATCH:
        return {'dispatch_count': 1, 'dispatch_amount': amount}
    if action == STAT_ACTION_SETTLE:
        return {'settle_count': 1, 'settle_amount': amount}
    if action == STAT_ACTION_REFUND:
        return {'refund_count': 1, 'refund_amount': amount}
    return {}


def update_staff_daily(merchant_id, staff_user_id, member_id, amount, action):
    """子客服日统计；老板操作不写此表。"""
    amount = Decimal(str(amount)) if amount else Decimal('0.00')
    fields = _action_fields(action, amount)
    if not fields:
        return

    today = date.today()
    with transaction.atomic():
        stat, _ = MerchantStaffDailyStats.objects.select_for_update().get_or_create(
            merchant_id=merchant_id,
            staff_user_id=staff_user_id,
            stat_date=today,
            defaults={
                'club_id': 'xq',
                'member_id': member_id,
                'year': today.year,
                'month': today.month,
                'day': today.day,
            },
        )
        update_kwargs = {}
        for k, v in fields.items():
            if k.endswith('_count'):
                update_kwargs[k] = F(k) + int(v)
            else:
                update_kwargs[k] = F(k) + v
        MerchantStaffDailyStats.query.filter(id=stat.id).update(**update_kwargs)


def sync_staff_stats_by_order_id(order_id, amount, action):
    """按订单派单归属同步子客服日统计（商家侧由 update_shangjia_daily 负责）。"""
    if not order_id:
        return
    amount = Decimal(str(amount)) if amount else Decimal('0.00')
    if amount <= 0:
        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

    update_staff_daily(
        disp.merchant_id,
        member.staff_user_id,
        member.id,
        amount,
        action,
    )
    if action == STAT_ACTION_DISPATCH:
        MerchantStaffMember.objects.filter(id=member.id).update(
            today_dispatch_count=F('today_dispatch_count') + 1,
            today_dispatch_amount=F('today_dispatch_amount') + amount,
        )
    elif action == STAT_ACTION_REFUND:
        try:
            release_dispatch_quota(order_id, amount, member.staff_user_id)
        except Exception:
            logger.warning('释放客服派单额度失败 order_id=%s', order_id, exc_info=True)


def update_merchant_and_staff_stats(merchant_id, staff_member, amount, action, order_id=None):
    """商家日统计必写；有 order_id 时按派单归属写客服统计，否则写操作人。"""
    update_shangjia_daily(merchant_id, amount, action, order_id=order_id)
    if order_id:
        return
    if staff_member:
        update_staff_daily(
            merchant_id,
            staff_member.staff_user_id,
            staff_member.id,
            amount,
            action,
        )


def get_staff_stats_payload(member):
    """子客服个人统计（今日 + 累计），供 /me 与首页展示。"""
    from django.db.models import Sum

    today = date.today()
    today_stat = MerchantStaffDailyStats.objects.filter(
        member_id=member.id, stat_date=today,
    ).first()
    total = MerchantStaffDailyStats.objects.filter(member_id=member.id).aggregate(
        dispatch_count=Sum('dispatch_count'),
        dispatch_amount=Sum('dispatch_amount'),
        settle_count=Sum('settle_count'),
        settle_amount=Sum('settle_amount'),
        refund_count=Sum('refund_count'),
        refund_amount=Sum('refund_amount'),
    )
    return {
        'today_dispatch_count': (
            today_stat.dispatch_count if today_stat else int(member.today_dispatch_count or 0)
        ),
        'today_dispatch_amount': str(
            today_stat.dispatch_amount if today_stat else (member.today_dispatch_amount or '0.00')
        ),
        'today_refund_count': today_stat.refund_count if today_stat else 0,
        'today_settle_count': today_stat.settle_count if today_stat else 0,
        'dispatch_count': total['dispatch_count'] or 0,
        'dispatch_amount': str(total['dispatch_amount'] or '0.00'),
        'settle_count': total['settle_count'] or 0,
        'settle_amount': str(total['settle_amount'] or '0.00'),
        'refund_count': total['refund_count'] or 0,
        'refund_amount': str(total['refund_amount'] or '0.00'),
    }


def bump_cancel_count(merchant_id, staff_member):
    if not staff_member:
        return
    today = date.today()
    with transaction.atomic():
        stat, _ = MerchantStaffDailyStats.objects.select_for_update().get_or_create(
            merchant_id=merchant_id,
            staff_user_id=staff_member.staff_user_id,
            stat_date=today,
            defaults={
                'club_id': 'xq',
                'member_id': staff_member.id,
                'year': today.year,
                'month': today.month,
                'day': today.day,
            },
        )
        MerchantStaffDailyStats.query.filter(id=stat.id).update(
            cancel_count=F('cancel_count') + 1,
        )


def bump_penalty_count(merchant_id, staff_member):
    if not staff_member:
        return
    today = date.today()
    with transaction.atomic():
        stat, _ = MerchantStaffDailyStats.objects.select_for_update().get_or_create(
            merchant_id=merchant_id,
            staff_user_id=staff_member.staff_user_id,
            stat_date=today,
            defaults={
                'club_id': 'xq',
                'member_id': staff_member.id,
                'year': today.year,
                'month': today.month,
                'day': today.day,
            },
        )
        MerchantStaffDailyStats.query.filter(id=stat.id).update(
            penalty_count=F('penalty_count') + 1,
        )
