"""抢单大厅假单：按俱乐部开关混排/过滤。"""
import hashlib
import logging
import random
import time
from datetime import datetime
from decimal import Decimal

from django.core.exceptions import ObjectDoesNotExist
from django.utils import timezone
from rest_framework.response import Response

from backend.utils import fmt_datetime, pick_leixing_id
from jituan.services.club_context import resolve_effective_club_id
from jituan.services.fake_grab_switch import (
    get_fake_yajin_hide_threshold,
    is_club_fake_grab_enabled,
)
from jituan.services.huiyuan_bundle import normalize_huiyuan_id, user_has_huiyuan_access
from orders.models import FakeGrabOrder

logger = logging.getLogger(__name__)

DEFAULT_DISPATCHER_AVATAR = 'beijing/morentouxiang.jpg'
# 展示顺序每 N 秒换一桶；同桶内全用户/全 worker 一致（不写库，无并发覆盖）
DEFAULT_SHUFFLE_INTERVAL = 120

MODE_OFF = 'off'
MODE_FAKE_ONLY = 'fake_only'
MODE_MIX = 'mix'
MODE_REAL_ONLY = 'real_only'


def _leixing_membership_meta(leixing_id):
    """返回 (required_huiyuan_id, yaoqiuleixing)。"""
    if leixing_id is None:
        return '', None
    try:
        from products.models import ShangpinLeixing
        row = ShangpinLeixing.query.filter(id=int(leixing_id)).values(
            'huiyuan_id', 'yaoqiuleixing',
        ).first()
        if not row:
            return '', None
        return (
            normalize_huiyuan_id(row.get('huiyuan_id')),
            row.get('yaoqiuleixing'),
        )
    except Exception:
        logger.exception('read ShangpinLeixing membership meta failed leixing_id=%s', leixing_id)
        return '', None


def _user_has_type_membership(user, club_id, leixing_id):
    required, _yaoqiu = _leixing_membership_meta(leixing_id)
    if not required:
        return False
    try:
        return bool(user_has_huiyuan_access(user.UserUID, required, club_id=club_id))
    except Exception:
        logger.exception(
            'user_has_huiyuan_access failed uid=%s required=%s club=%s',
            getattr(user, 'UserUID', ''), required, club_id,
        )
        return False


def resolve_fake_pool_mode(user, club_id=None, leixing_id=None):
    """
    - off：俱乐部未开 → 只真单
    - fake_only：封禁 → 只假单
    - real_only：有对应会员，或押金≥门槛 → 过滤假单
    - mix：未充对应会员且押金未达门槛 → 真单+假单
    """
    cid = (club_id or '').strip()
    if not cid:
        return MODE_OFF

    try:
        enabled = is_club_fake_grab_enabled(cid)
    except Exception:
        logger.exception('is_club_fake_grab_enabled failed club=%s', cid)
        return MODE_OFF
    if not enabled:
        return MODE_OFF

    try:
        dashou = user.DashouProfile
    except ObjectDoesNotExist:
        return MODE_FAKE_ONLY
    except Exception:
        logger.exception('read DashouProfile failed uid=%s', getattr(user, 'UserUID', ''))
        return MODE_FAKE_ONLY

    if int(getattr(dashou, 'zhanghaozhuangtai', 0) or 0) != 1:
        return MODE_FAKE_ONLY

    if leixing_id is not None and _user_has_type_membership(user, cid, leixing_id):
        return MODE_REAL_ONLY

    try:
        yajin = Decimal(str(getattr(dashou, 'yajin', 0) or 0))
    except Exception:
        yajin = Decimal('0')
    if yajin >= get_fake_yajin_hide_threshold(cid):
        return MODE_REAL_ONLY

    return MODE_MIX


def dashou_should_use_fake_pool(user, club_id=None, leixing_id=None):
    """兼容旧调用：是否整页只假单。"""
    return resolve_fake_pool_mode(user, club_id=club_id, leixing_id=leixing_id) == MODE_FAKE_ONLY


def list_formatted_fake_orders(club_id, leixing_id):
    rows, anchor_dt = _load_fake_rows_stable_order(club_id, leixing_id)
    return [_format_fake_row(r, anchor_dt) for r in rows]


def _stable_int_seed(*parts):
    raw = '|'.join('' if p is None else str(p) for p in parts)
    return int(hashlib.md5(raw.encode('utf-8')).hexdigest()[:8], 16)


def _shuffle_interval_seconds():
    try:
        from orders.models import FakeGrabOrderShuffleState
        row = FakeGrabOrderShuffleState.objects.filter(pk=1).only('IntervalSeconds').first()
        if row and row.IntervalSeconds:
            return max(1, int(row.IntervalSeconds))
    except Exception:
        pass
    return DEFAULT_SHUFFLE_INTERVAL


def _display_time_str_for_order(order_id, anchor_dt):
    """同一假单在打乱窗口内展示时间固定（md5，不依赖 PYTHONHASHSEED）。"""
    seed = _stable_int_seed(order_id)
    seconds_ago = 120 + (seed % 181)
    if anchor_dt is None:
        base_ts = time.time()
    elif timezone.is_aware(anchor_dt):
        base_ts = anchor_dt.timestamp()
    else:
        try:
            base_ts = timezone.make_aware(anchor_dt, timezone.get_current_timezone()).timestamp()
        except Exception:
            base_ts = time.time()
    display_dt = datetime.fromtimestamp(
        base_ts - seconds_ago,
        tz=timezone.get_current_timezone(),
    )
    return fmt_datetime(display_dt)


def _load_fake_rows_stable_order(club_id, leixing_id):
    """
    按俱乐部+类型加载假单，用「时间桶 + md5」稳定打乱：
    - 同桶内所有进程/用户顺序一致
    - 不读写共享 JSON，避免并发刷新把列表写空/写丢
    """
    cid = (club_id or '').strip()
    qs = FakeGrabOrder.query.filter(ClubID=cid)
    if leixing_id is not None:
        try:
            qs = qs.filter(ProductTypeID=int(leixing_id))
        except (TypeError, ValueError):
            qs = qs.filter(ProductTypeID=leixing_id)

    # 先稳定取出，再按桶打乱（避免 DB 顺序漂移）
    all_rows = list(qs.order_by('-SortOrder', 'OrderID'))
    id_to_row = {r.OrderID: r for r in all_rows if r.OrderID}
    all_ids = list(id_to_row.keys())

    interval = _shuffle_interval_seconds()
    bucket = int(time.time()) // interval
    rng = random.Random(_stable_int_seed(cid, leixing_id, bucket))
    shuffled_ids = list(all_ids)
    rng.shuffle(shuffled_ids)

    anchor_dt = datetime.fromtimestamp(
        bucket * interval,
        tz=timezone.get_current_timezone(),
    )
    ordered = [id_to_row[oid] for oid in shuffled_ids if oid in id_to_row]
    if len(ordered) != len(all_ids):
        logger.warning(
            'fake pool order mismatch club=%s leixing=%s ids=%s ordered=%s',
            cid, leixing_id, len(all_ids), len(ordered),
        )
    return ordered, anchor_dt


def _format_fake_row(row, anchor_dt=None):
    """字段与 DashouDingdanHuoquView 真实单列表保持一致。"""
    avatar = (getattr(row, 'DispatcherAvatar', None) or '').strip() or DEFAULT_DISPATCHER_AVATAR
    platform = int(row.Platform or 1)
    oid = row.OrderID
    price = float(row.Amount or 0)
    ct = _display_time_str_for_order(oid, anchor_dt)
    zid = (row.DispatcherUserID or '').strip()
    sj_name = (getattr(row, 'MerchantNickname', None) or '').strip()

    return {
        'dingdan_id': oid,
        'zhuangtai': 1,
        'pingtai': platform,
        'dashou_fencheng': price,
        'leixing_id': row.ProductTypeID or 0,
        'tupian': avatar,
        'yaoqiuleixing': 0,
        'huiyuan_id': '',
        # 假单始终展示价格（前端 hasRequiredMember=true 才显示金额）
        'hasRequiredMember': True,
        'has_required_member': True,
        'is_fake': True,
        'yajin': 0.0,
        'jieshao': row.Description or '',
        'beizhu': row.Remark or '',
        'creat_time': ct,
        'create_time': ct,
        'sjnicheng': sj_name if platform == 2 else '',
        'sj_avatar': avatar if platform == 2 else '',
        'zhiding_uid': zid,
        'zhiding_avatar': avatar,
        'zhiding_nicheng': '',
        'xuqiu_biaoqian': [],
        'dashou_biaoqian': [],
        'shangjia_biaoqian': [],
        'shangjia_identity_biaoqian': [],
        'zhiding_identity_biaoqian': [],
        'shangjia_youzhi': bool(row.IsPremiumMerchant) if platform == 2 else False,
    }


def build_fake_order_pool_response(request):
    data = request.data
    leixing_id = pick_leixing_id(data)
    page = max(1, int(data.get('page', 1)))
    page_size = max(1, min(int(data.get('page_size', 10)), 50))

    club_id = resolve_effective_club_id(request, getattr(request, 'user', None))

    rows, anchor_dt = _load_fake_rows_stable_order(club_id, leixing_id)

    total = len(rows)
    offset = (page - 1) * page_size
    page_rows = rows[offset:offset + page_size]

    formatted_list = [_format_fake_row(r, anchor_dt) for r in page_rows]
    has_more = (page * page_size) < total

    return Response({
        'code': 200,
        'msg': '获取成功',
        'data': {
            'list': formatted_list,
            'has_more': has_more,
            'total': total,
            'current_page': page,
            'page_size': page_size,
            'total_pages': (total + page_size - 1) // page_size if page_size else 0,
            'type_pending_counts': {},
            'pool_pending_total': 0,
            'team_pending_count': 0,
            'is_fake_pool': True,
        },
    })
