"""后台假单管理（按俱乐部 + 商品类型）。"""
import logging
import os
import random
import time
import uuid
from decimal import Decimal

from jituan.constants import DATA_SCOPE_ALL
from jituan.services.club_context import (
    club_id_for_write,
    resolve_club_id_from_request,
    resolve_club_scope,
)
from jituan.services.club_user_access import list_response_meta
from orders.models import FakeGrabOrder, FakeGrabOrderShuffleState
from orders.services.fake_order_pool import DEFAULT_DISPATCHER_AVATAR
from products.models import ShangpinLeixing

logger = logging.getLogger(__name__)

CLUB_WRITE_SCOPE_MSG = '当前为集团汇总视图，请先在顶栏切换到具体俱乐部后再操作'
CLUB_READ_SCOPE_MSG = '请先在顶栏切换到具体小程序/俱乐部后再操作'
PRODUCT_PERMS = ('2200a',)
SHUFFLE_STATE_PK = 1


def _scope_key(club_id, leixing_id):
    """与历史打乱缓存 key 一致：club|leixing。"""
    lid = leixing_id if leixing_id is not None else 'all'
    return f'{club_id}|{lid}'


def club_read_blocked(request):
    return resolve_club_scope(request) == DATA_SCOPE_ALL


def club_write_blocked(request):
    return resolve_club_scope(request) == DATA_SCOPE_ALL


def _gen_order_id():
    while True:
        oid = f'JD{int(time.time() * 1000)}{random.randint(1000, 9999)}'
        if not FakeGrabOrder.query.filter(OrderID=oid).exists():
            return oid


def invalidate_fake_order_shuffle(club_id, leixing_id=None):
    """假单增删改后清除对应打乱缓存，下次读取自动重排。"""
    try:
        state = FakeGrabOrderShuffleState.objects.get(pk=SHUFFLE_STATE_PK)
    except FakeGrabOrderShuffleState.DoesNotExist:
        return
    seq_map = dict(state.OrderSequence or {})
    if leixing_id is not None:
        seq_map.pop(_scope_key(club_id, leixing_id), None)
    else:
        prefix = f'{club_id}|'
        for key in list(seq_map.keys()):
            if key.startswith(prefix):
                seq_map.pop(key, None)
    state.OrderSequence = seq_map
    state.save(update_fields=['OrderSequence', 'UpdateTime'])


def _leixing_name_map():
    return {
        lx.id: (lx.jieshao or f'类型{lx.id}')
        for lx in ShangpinLeixing.query.exclude(shenhezhuangtai=2)
    }


def build_leixing_options():
    """全部可用商品类型（非审核专用），假单可绑定任意类型。"""
    options = []
    for lx in ShangpinLeixing.query.exclude(shenhezhuangtai=2).order_by('-paixu', 'id'):
        options.append({
            'id': lx.id,
            'jieshao': lx.jieshao or '',
            'tupian_url': lx.tupian_url or '',
            'bankuai_id': lx.bankuai_id,
        })
    return options


def _row_to_dict(row, leixing_names=None):
    leixing_names = leixing_names or _leixing_name_map()
    return {
        'order_id': row.OrderID,
        'dingdan_id': row.OrderID,
        'amount': str(row.Amount or 0),
        'jine': str(row.Amount or 0),
        'leixing_id': row.ProductTypeID,
        'leixing_name': leixing_names.get(row.ProductTypeID, f'类型{row.ProductTypeID}'),
        'jieshao': row.Description or '',
        'beizhu': row.Remark or '',
        'paidan_yonghuid': row.DispatcherUserID or '',
        'paidan_touxiang': row.DispatcherAvatar or DEFAULT_DISPATCHER_AVATAR,
        'shangjia_nicheng': row.MerchantNickname or '',
        'is_youzhi_shangjia': bool(row.IsPremiumMerchant),
        'fadan_pingtai': int(row.Platform or 1),
        'platform_label': '平台发单' if int(row.Platform or 1) == 1 else '商家发单',
        'sort_order': int(row.SortOrder or 0),
        'club_id': row.ClubID,
        'CreateTime': row.CreateTime.isoformat() if row.CreateTime else None,
        'UpdateTime': row.UpdateTime.isoformat() if row.UpdateTime else None,
    }


def build_fake_order_list_payload(request, leixing_id=None, page=1, page_size=20):
    if club_read_blocked(request):
        return {
            'list': [],
            'total': 0,
            'page': page,
            'page_size': page_size,
            'club_id': resolve_club_id_from_request(request),
            'scope': resolve_club_scope(request),
            'scope_error': CLUB_READ_SCOPE_MSG,
            'leixing_options': build_leixing_options(),
            'fake_grab_enabled': False,
            'fake_yajin_hide_threshold': 10,
            **list_response_meta(request),
        }

    club_id = resolve_club_id_from_request(request)
    page = max(1, int(page or 1))
    page_size = min(100, max(1, int(page_size or 20)))

    qs = FakeGrabOrder.query.filter(ClubID=club_id)
    if leixing_id not in (None, ''):
        qs = qs.filter(ProductTypeID=int(leixing_id))
    qs = qs.order_by('-SortOrder', '-CreateTime')
    total = qs.count()
    offset = (page - 1) * page_size
    rows = list(qs[offset:offset + page_size])
    names = _leixing_name_map()

    from jituan.services.fake_grab_switch import (
        get_fake_yajin_hide_threshold,
        is_club_fake_grab_enabled,
    )

    return {
        'list': [_row_to_dict(r, names) for r in rows],
        'total': total,
        'page': page,
        'page_size': page_size,
        'club_id': club_id,
        'scope': resolve_club_scope(request),
        'leixing_options': build_leixing_options(),
        'fake_grab_enabled': is_club_fake_grab_enabled(club_id),
        'fake_yajin_hide_threshold': float(get_fake_yajin_hide_threshold(club_id)),
        **list_response_meta(request),
    }


def set_fake_grab_enabled(request, enabled):
    """开启/关闭本俱乐部打手侧假单功能。"""
    if club_write_blocked(request):
        return None, CLUB_WRITE_SCOPE_MSG

    from jituan.models import Club
    from jituan.services.fake_grab_switch import (
        get_fake_yajin_hide_threshold,
        is_club_fake_grab_enabled,
        set_club_fake_grab_enabled,
    )

    club_id = club_id_for_write(request)
    club = Club.query.filter(club_id=club_id).first()
    if not club:
        return None, '俱乐部不存在'

    set_club_fake_grab_enabled(club, bool(enabled))
    club.save(update_fields=['config_json'])
    return {
        'club_id': club_id,
        'fake_grab_enabled': is_club_fake_grab_enabled(club_id),
        'fake_yajin_hide_threshold': float(get_fake_yajin_hide_threshold(club_id)),
    }, None


def set_fake_yajin_threshold(request, threshold):
    """设置押金 ≥ 该值时过滤假单。"""
    if club_write_blocked(request):
        return None, CLUB_WRITE_SCOPE_MSG

    from jituan.models import Club
    from jituan.services.fake_grab_switch import (
        get_fake_yajin_hide_threshold,
        is_club_fake_grab_enabled,
        set_fake_yajin_hide_threshold,
    )

    club_id = club_id_for_write(request)
    club = Club.query.filter(club_id=club_id).first()
    if not club:
        return None, '俱乐部不存在'

    val = set_fake_yajin_hide_threshold(club, threshold)
    club.save(update_fields=['config_json'])
    return {
        'club_id': club_id,
        'fake_grab_enabled': is_club_fake_grab_enabled(club_id),
        'fake_yajin_hide_threshold': float(val),
    }, None


def _parse_decimal(value, field_name='金额'):
    try:
        val = Decimal(str(value))
        if val < 0:
            raise ValueError
        return val
    except Exception:
        raise ValueError(f'{field_name}格式错误')


def _validate_leixing_id(leixing_id):
    try:
        lid = int(leixing_id)
    except (TypeError, ValueError):
        return None, '请选择商品类型'
    if not ShangpinLeixing.query.filter(id=lid).exclude(shenhezhuangtai=2).exists():
        return None, '商品类型不存在或为审核专用'
    return lid, None


def create_fake_order(request, data):
    if club_write_blocked(request):
        return None, CLUB_WRITE_SCOPE_MSG

    club_id = club_id_for_write(request)
    leixing_id, err = _validate_leixing_id(data.get('leixing_id'))
    if err:
        return None, err

    try:
        amount = _parse_decimal(data.get('amount') or data.get('jine'), '价格')
    except ValueError as e:
        return None, str(e)

    platform = int(data.get('fadan_pingtai') or data.get('platform') or 1)
    if platform not in (1, 2):
        return None, '发单平台无效'

    row = FakeGrabOrder.query.create(
        OrderID=_gen_order_id(),
        Amount=amount,
        ProductTypeID=leixing_id,
        Description=(data.get('jieshao') or '').strip(),
        Remark=(data.get('beizhu') or '').strip(),
        DispatcherUserID=(data.get('paidan_yonghuid') or '').strip(),
        DispatcherAvatar=(data.get('paidan_touxiang') or '').strip() or DEFAULT_DISPATCHER_AVATAR,
        MerchantNickname=(data.get('shangjia_nicheng') or '').strip() if platform == 2 else '',
        IsPremiumMerchant=bool(data.get('is_youzhi_shangjia')) if platform == 2 else False,
        Platform=platform,
        ClubID=club_id,
        SortOrder=int(data.get('sort_order') or 0),
    )
    invalidate_fake_order_shuffle(club_id, leixing_id)
    return _row_to_dict(row), None


def update_fake_order(request, order_id, data):
    if club_write_blocked(request):
        return None, CLUB_WRITE_SCOPE_MSG

    club_id = club_id_for_write(request)
    order_id = (order_id or '').strip()
    if not order_id:
        return None, '缺少订单ID'

    try:
        row = FakeGrabOrder.objects.get(OrderID=order_id, ClubID=club_id)
    except FakeGrabOrder.DoesNotExist:
        return None, '假单不存在或不属于当前俱乐部'

    old_leixing = row.ProductTypeID
    update_fields = ['UpdateTime']

    if 'leixing_id' in data and data.get('leixing_id') not in (None, ''):
        leixing_id, err = _validate_leixing_id(data.get('leixing_id'))
        if err:
            return None, err
        row.ProductTypeID = leixing_id
        update_fields.append('ProductTypeID')

    if 'amount' in data or 'jine' in data:
        try:
            row.Amount = _parse_decimal(data.get('amount') or data.get('jine'), '价格')
        except ValueError as e:
            return None, str(e)
        update_fields.append('Amount')

    if 'jieshao' in data:
        row.Description = (data.get('jieshao') or '').strip()
        update_fields.append('Description')
    if 'beizhu' in data:
        row.Remark = (data.get('beizhu') or '').strip()
        update_fields.append('Remark')
    if 'paidan_yonghuid' in data:
        row.DispatcherUserID = (data.get('paidan_yonghuid') or '').strip()
        update_fields.append('DispatcherUserID')
    if 'paidan_touxiang' in data:
        row.DispatcherAvatar = (data.get('paidan_touxiang') or '').strip() or DEFAULT_DISPATCHER_AVATAR
        update_fields.append('DispatcherAvatar')
    if 'sort_order' in data:
        row.SortOrder = int(data.get('sort_order') or 0)
        update_fields.append('SortOrder')

    if 'fadan_pingtai' in data or 'platform' in data:
        platform = int(data.get('fadan_pingtai') or data.get('platform') or row.Platform or 1)
        if platform not in (1, 2):
            return None, '发单平台无效'
        row.Platform = platform
        update_fields.append('Platform')
        if platform == 1:
            row.MerchantNickname = ''
            row.IsPremiumMerchant = False
            update_fields.extend(['MerchantNickname', 'IsPremiumMerchant'])

    if row.Platform == 2:
        if 'shangjia_nicheng' in data:
            row.MerchantNickname = (data.get('shangjia_nicheng') or '').strip()
            update_fields.append('MerchantNickname')
        if 'is_youzhi_shangjia' in data:
            row.IsPremiumMerchant = bool(data.get('is_youzhi_shangjia'))
            update_fields.append('IsPremiumMerchant')

    row.save(update_fields=list(set(update_fields)))
    invalidate_fake_order_shuffle(club_id, row.ProductTypeID)
    if old_leixing != row.ProductTypeID:
        invalidate_fake_order_shuffle(club_id, old_leixing)
    return _row_to_dict(row), None


def delete_fake_order(request, order_id):
    if club_write_blocked(request):
        return None, CLUB_WRITE_SCOPE_MSG

    club_id = club_id_for_write(request)
    order_id = (order_id or '').strip()
    if not order_id:
        return None, '缺少订单ID'

    try:
        row = FakeGrabOrder.objects.get(OrderID=order_id, ClubID=club_id)
    except FakeGrabOrder.DoesNotExist:
        return None, '假单不存在或不属于当前俱乐部'

    leixing_id = row.ProductTypeID
    row.delete()
    invalidate_fake_order_shuffle(club_id, leixing_id)
    return {'order_id': order_id}, None


def upload_fake_order_avatar(request, order_id, file_obj):
    if club_write_blocked(request):
        return None, CLUB_WRITE_SCOPE_MSG

    from utils.oss_utils import upload_to_oss, validate_image

    club_id = club_id_for_write(request)
    order_id = (order_id or '').strip()
    if not order_id or not file_obj:
        return None, '参数不完整'

    ok, msg = validate_image(file_obj)
    if not ok:
        return None, msg

    try:
        row = FakeGrabOrder.objects.get(OrderID=order_id, ClubID=club_id)
    except FakeGrabOrder.DoesNotExist:
        return None, '假单不存在或不属于当前俱乐部'

    ext = os.path.splitext(getattr(file_obj, 'name', '') or '')[1].lower()
    if ext not in ('.png', '.jpg', '.jpeg', '.webp', '.gif'):
        ext = '.png'
    rel_path = f'club/{club_id}/fake_grab_order/{order_id}_{uuid.uuid4().hex}{ext}'
    if not upload_to_oss(file_obj, rel_path):
        return None, '上传 OSS 失败'

    row.DispatcherAvatar = rel_path
    row.save(update_fields=['DispatcherAvatar', 'UpdateTime'])
    invalidate_fake_order_shuffle(club_id, row.ProductTypeID)
    return {'order_id': order_id, 'paidan_touxiang': rel_path}, None
