"""客服改抢单要求（会员/押金门槛）— 隔离新接口，不影响旧抢单/支付主路径。"""
import json
import logging
from decimal import Decimal, InvalidOperation

from django.db import transaction
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser
from rest_framework.response import Response
from rest_framework.views import APIView

from backend.utils import verify_kefu_permission, has_perm_code
from jituan.constants import (
    CLUB_ID_DEFAULT,
    PERM_GRAB_REQUIREMENT_EDIT,
)
from jituan.models import AdminAuditLog
from jituan.services.club_context import resolve_club_id_from_request
from orders.models import Order
from products.models import Huiyuan, Shangpin

logger = logging.getLogger(__name__)

ALLOWED_ORDER_STATUSES = frozenset({1, 7})
GRAB_TYPE_MEMBER = 1
GRAB_TYPE_DEPOSIT = 2


def _client_ip(request):
    xff = (request.META.get('HTTP_X_FORWARDED_FOR') or '').split(',')[0].strip()
    return xff or (request.META.get('REMOTE_ADDR') or '')[:64]


def _normalize_club_id(club_id):
    cid = (club_id or '').strip()
    return cid or CLUB_ID_DEFAULT


def _require_002ad(request):
    phone = (request.data.get('phone') or request.data.get('username') or '').strip()
    kefu, permissions = verify_kefu_permission(request, phone or None)
    if kefu is None:
        return None, None, permissions
    if not has_perm_code(permissions, PERM_GRAB_REQUIREMENT_EDIT):
        return None, None, Response({
            'code': 403,
            'msg': f'您无权修改抢单要求（需要 {PERM_GRAB_REQUIREMENT_EDIT}）',
        })
    return kefu, permissions, None


def _parse_grab_payload(data):
    """返回 (yaoqiuleixing, huiyuan_id, yongjin, error_response)。"""
    try:
        yaoqiu = int(data.get('yaoqiuleixing'))
    except (TypeError, ValueError):
        return None, None, None, Response({'code': 400, 'msg': '抢单要求类型无效（须为1会员或2押金）'})
    if yaoqiu not in (GRAB_TYPE_MEMBER, GRAB_TYPE_DEPOSIT):
        return None, None, None, Response({'code': 400, 'msg': '抢单要求类型无效（须为1会员或2押金）'})

    if yaoqiu == GRAB_TYPE_MEMBER:
        huiyuan_id = (data.get('huiyuan_id') or '').strip()
        if not huiyuan_id:
            return None, None, None, Response({'code': 400, 'msg': '会员要求须填写会员ID'})
        if len(huiyuan_id) > 6:
            return None, None, None, Response({'code': 400, 'msg': '会员ID过长'})
        if not Huiyuan.query.filter(huiyuan_id=huiyuan_id).exists():
            return None, None, None, Response({'code': 400, 'msg': f'会员ID不存在：{huiyuan_id}'})
        return yaoqiu, huiyuan_id, None, None

    raw = data.get('yongjin', data.get('yajin'))
    if raw is None or raw == '':
        return None, None, None, Response({'code': 400, 'msg': '押金要求须填写押金金额'})
    try:
        yongjin = Decimal(str(raw)).quantize(Decimal('0.01'))
    except (InvalidOperation, ValueError, TypeError):
        return None, None, None, Response({'code': 400, 'msg': '押金金额格式错误'})
    if yongjin < 0:
        return None, None, None, Response({'code': 400, 'msg': '押金金额不能为负'})
    return yaoqiu, None, yongjin, None


def _snapshot_order(order):
    return {
        'yaoqiuleixing': order.GrabRequirement,
        'huiyuan_id': order.MembershipID or '',
        'yongjin': str(order.CommissionReq) if order.CommissionReq is not None else None,
    }


def _snapshot_product_fields(yaoqiu, huiyuan_id, yongjin):
    return {
        'yaoqiuleixing': yaoqiu,
        'huiyuan_id': huiyuan_id or '',
        'yongjin': str(yongjin) if yongjin is not None else None,
    }


def _write_audit(*, request, club_id, action, resource_type, resource_id, before, after, remark=''):
    try:
        op = getattr(request.user, 'UserUID', None) or getattr(request.user, 'Phone', '') or ''
        AdminAuditLog.query.create(
            club_id=_normalize_club_id(club_id),
            operator_yonghuid=str(op)[:16],
            action=action,
            resource_type=resource_type,
            resource_id=str(resource_id)[:64],
            field_name='yaoqiuleixing,huiyuan_id,yongjin',
            value_before=json.dumps(before, ensure_ascii=False)[:2000],
            value_after=json.dumps(after, ensure_ascii=False)[:2000],
            request_ip=_client_ip(request),
            remark=(remark or '')[:500],
        )
    except Exception as e:
        logger.warning('抢单要求审计写入失败: %s', e)


class KefuUpdateOrderGrabRequirementView(APIView):
    """
    POST /yonghu/kefu_gai_qiangdan_yaoqiu
    改单笔平台订单抢单要求。权限 002ad；按俱乐部闸门各管各的；仅状态 1/7。
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        kefu, _permissions, err = _require_002ad(request)
        if err:
            return err

        dingdan_id = (request.data.get('dingdan_id') or '').strip()
        if not dingdan_id:
            return Response({'code': 400, 'msg': '缺少订单ID'})

        yaoqiu, huiyuan_id, yongjin, perr = _parse_grab_payload(request.data)
        if perr:
            return perr

        try:
            with transaction.atomic():
                order = (
                    Order.query.select_for_update()
                    .filter(OrderID=dingdan_id)
                    .first()
                )
                if not order:
                    return Response({'code': 404, 'msg': '订单不存在'})

                from jituan.services.club_user_access import forbid_if_order_mutate_out_of_scope
                scope_deny = forbid_if_order_mutate_out_of_scope(request, order)
                if scope_deny:
                    return scope_deny

                order_club = _normalize_club_id(getattr(order, 'ClubID', None))

                if int(order.Platform or 0) != 1:
                    return Response({'code': 400, 'msg': '仅平台订单可修改抢单要求'})

                if int(order.Status or 0) not in ALLOWED_ORDER_STATUSES:
                    return Response({
                        'code': 400,
                        'msg': '仅下单中(1)/指定中(7)的订单可修改抢单要求',
                    })

                before = _snapshot_order(order)
                order.GrabRequirement = yaoqiu
                if yaoqiu == GRAB_TYPE_MEMBER:
                    order.MembershipID = huiyuan_id
                    order.CommissionReq = None
                else:
                    order.MembershipID = None
                    order.CommissionReq = yongjin
                order.save(update_fields=[
                    'GrabRequirement', 'MembershipID', 'CommissionReq', 'UpdateTime',
                ])

                # 并发接单后状态可能已变：再读一次，若已不在允许状态则回滚
                order.refresh_from_db()
                if int(order.Status or 0) not in ALLOWED_ORDER_STATUSES:
                    raise RuntimeError('ORDER_STATUS_CHANGED')

                after = _snapshot_order(order)
                phone = getattr(request.user, 'Phone', '') or ''
                _write_audit(
                    request=request,
                    club_id=order_club,
                    action='grab_requirement_order',
                    resource_type='order',
                    resource_id=dingdan_id,
                    before=before,
                    after=after,
                    remark=f'客服{phone}改平台订单抢单要求',
                )
        except RuntimeError as e:
            if str(e) == 'ORDER_STATUS_CHANGED':
                return Response({
                    'code': 409,
                    'msg': '订单状态已变更，无法修改抢单要求，请刷新后重试',
                })
            raise
        except Exception:
            logger.exception('改订单抢单要求失败 dingdan_id=%s', dingdan_id)
            return Response({'code': 500, 'msg': '修改失败'})

        return Response({
            'code': 0,
            'msg': '修改成功',
            'data': {
                'dingdan_id': dingdan_id,
                'yaoqiuleixing': yaoqiu,
                'huiyuan_id': huiyuan_id or '',
                'yajin': float(yongjin) if yongjin is not None else None,
            },
        })


class KefuBatchProductGrabRequirementView(APIView):
    """
    POST /yonghu/kefu_batch_qiangdan_yaoqiu
    预览/确认：批量改本店某商品类型下 Shangpin 的抢单要求字段。
    confirm 缺省/false 只预览；true 才写库。不碰全局 ShangpinLeixing。
    须切换到具体俱乐部（不跨店）。
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        kefu, _permissions, err = _require_002ad(request)
        if err:
            return err

        from jituan.constants import DATA_SCOPE_ALL
        from jituan.services.club_context import resolve_club_scope

        if resolve_club_scope(request) == DATA_SCOPE_ALL:
            return Response({
                'code': 403,
                'msg': '请切换到具体俱乐部后再批量修改商品抢单要求',
            })

        club_id = _normalize_club_id(resolve_club_id_from_request(request))

        try:
            leixing_id = int(request.data.get('leixing_id'))
        except (TypeError, ValueError):
            return Response({'code': 400, 'msg': '缺少或无效的商品类型ID'})

        yaoqiu, huiyuan_id, yongjin, perr = _parse_grab_payload(request.data)
        if perr:
            return perr

        confirm = request.data.get('confirm') in (True, 'true', '1', 1, 'on')

        qs = Shangpin.query.filter(club_id=club_id, leixing_id=leixing_id)
        total = qs.count()
        samples = list(qs.order_by('id').values(
            'id', 'biaoqian', 'yaoqiuleixing', 'huiyuan_id', 'yongjin',
        )[:5])
        for row in samples:
            if row.get('yongjin') is not None:
                row['yongjin'] = float(row['yongjin'])

        preview = {
            'club_id': club_id,
            'leixing_id': leixing_id,
            'affected_count': total,
            'samples': samples,
            'will_set': _snapshot_product_fields(yaoqiu, huiyuan_id, yongjin),
        }

        if not confirm:
            return Response({'code': 0, 'msg': '预览成功（未写入）', 'data': preview})

        if total == 0:
            return Response({'code': 400, 'msg': '该俱乐部下该类型暂无商品可改'})

        updates = {
            'yaoqiuleixing': yaoqiu,
            'huiyuan_id': huiyuan_id if yaoqiu == GRAB_TYPE_MEMBER else None,
            'yongjin': yongjin if yaoqiu == GRAB_TYPE_DEPOSIT else None,
        }

        try:
            with transaction.atomic():
                updated = Shangpin.query.filter(
                    club_id=club_id, leixing_id=leixing_id,
                ).update(**updates)
                phone = getattr(request.user, 'Phone', '') or ''
                _write_audit(
                    request=request,
                    club_id=club_id,
                    action='grab_requirement_product_batch',
                    resource_type='shangpin_leixing',
                    resource_id=f'{club_id}:{leixing_id}',
                    before={'affected_count': total, 'samples': samples},
                    after={**updates, 'updated_count': updated},
                    remark=f'客服{phone}批量改商品抢单要求 count={updated}',
                )
        except Exception:
            logger.exception(
                '批量改商品抢单要求失败 club=%s leixing=%s', club_id, leixing_id,
            )
            return Response({'code': 500, 'msg': '批量修改失败'})

        preview['updated_count'] = updated
        return Response({'code': 0, 'msg': f'已更新 {updated} 个商品', 'data': preview})
