"""管事自助更换组长：配额、校验、换绑。"""
import logging

from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from django.db.models import F

from jituan.services.club_context import resolve_effective_club_id
from jituan.services.invite_guard import assert_invite_same_club
from users.models import GuanshiChangeLeaderLog, GuanshiChangeLeaderQuota, UserGuanshi, UserZuzhang
from users.business_models import User

logger = logging.getLogger(__name__)

DEFAULT_QUOTA = 1


def _guanshi_display_name(user):
    try:
        return (user.BossProfile.nickname or '').strip() or user.UserUID
    except ObjectDoesNotExist:
        return user.UserUID


def _zuzhang_brief(uid):
    if not uid:
        return None
    try:
        u = User.query.get(UserUID=uid)
    except User.DoesNotExist:
        return {'uid': uid, 'nicheng': '未知', 'touxiang': ''}
    try:
        nicheng = u.BossProfile.nickname or '组长'
    except ObjectDoesNotExist:
        nicheng = '组长'
    return {
        'uid': u.UserUID,
        'nicheng': nicheng,
        'touxiang': u.Avatar or '',
    }


def get_or_create_quota(club_id, guanshi_uid):
    club_id = (club_id or '').strip()
    guanshi_uid = (guanshi_uid or '').strip()
    obj, _ = GuanshiChangeLeaderQuota.objects.get_or_create(
        club_id=club_id,
        guanshi_uid=guanshi_uid,
        defaults={'total_quota': DEFAULT_QUOTA, 'used_count': 0},
    )
    return obj


def quota_payload(quota):
    return {
        'total_quota': int(quota.total_quota or 0),
        'used_count': int(quota.used_count or 0),
        'remain_quota': quota.remain_quota,
    }


def build_change_leader_info(request, user):
    """小程序 info 接口数据。"""
    try:
        guanshi = user.GuanshiProfile
    except ObjectDoesNotExist:
        return {'ok': False, 'code': 403, 'msg': '您还不是管事'}

    if guanshi.zhuangtai != 1:
        return {'ok': False, 'code': 403, 'msg': '管事账号已禁用，无法更换组长'}

    club_id = resolve_effective_club_id(request, user)
    quota = get_or_create_quota(club_id, user.UserUID)
    return {
        'ok': True,
        'code': 200,
        'msg': 'ok',
        'data': {
            'club_id': club_id,
            'current_zuzhang': _zuzhang_brief(guanshi.yaoqingren),
            'quota': quota_payload(quota),
        },
    }


def change_leader_by_invite(request, user, invite_code, source='miniapp', operator=None):
    """
    用组长邀请码换绑。成功返回 data；失败返回 ok=False。
    仅更新管事 yaoqingren，不改名下打手。
    """
    invite_code = (invite_code or '').strip()
    if not invite_code:
        return {'ok': False, 'code': 400, 'msg': '请输入组长邀请码'}
    if len(invite_code) > 100:
        return {'ok': False, 'code': 400, 'msg': '邀请码长度超过限制'}

    try:
        guanshi = user.GuanshiProfile
    except ObjectDoesNotExist:
        return {'ok': False, 'code': 403, 'msg': '您还不是管事'}

    if guanshi.zhuangtai != 1:
        return {'ok': False, 'code': 403, 'msg': '管事账号已禁用，无法更换组长'}

    try:
        zuzhang = UserZuzhang.query.select_related('user').get(yaoqingma=invite_code)
    except UserZuzhang.DoesNotExist:
        return {'ok': False, 'code': 404, 'msg': '邀请码无效或不存在'}

    if zuzhang.zhuangtai != 1:
        return {'ok': False, 'code': 403, 'msg': '该邀请码对应的组长账号已被禁用'}

    new_uid = zuzhang.user.UserUID
    if new_uid == user.UserUID:
        return {'ok': False, 'code': 400, 'msg': '不能将自己设为组长'}

    old_uid = (guanshi.yaoqingren or '').strip()
    if old_uid and old_uid == new_uid:
        return {'ok': False, 'code': 400, 'msg': '已是该组长，无需更换'}

    ok, invite_msg = assert_invite_same_club(request, zuzhang.user, user)
    if not ok:
        return {'ok': False, 'code': 403, 'msg': invite_msg}

    club_id = resolve_effective_club_id(request, user)
    op = (operator or user.UserUID or '').strip()

    with transaction.atomic():
        quota = (
            GuanshiChangeLeaderQuota.objects
            .select_for_update()
            .filter(club_id=club_id, guanshi_uid=user.UserUID)
            .first()
        )
        if not quota:
            quota = GuanshiChangeLeaderQuota.objects.create(
                club_id=club_id,
                guanshi_uid=user.UserUID,
                total_quota=DEFAULT_QUOTA,
                used_count=0,
            )
            quota = (
                GuanshiChangeLeaderQuota.objects
                .select_for_update()
                .get(pk=quota.pk)
            )

        if quota.remain_quota <= 0:
            return {'ok': False, 'code': 403, 'msg': '更换次数已用完，请联系客服增加次数'}

        # 再读一次管事行，防并发
        guanshi = (
            UserGuanshi.query
            .select_for_update()
            .select_related('user')
            .get(pk=guanshi.pk)
        )
        old_uid = (guanshi.yaoqingren or '').strip()
        if old_uid == new_uid:
            return {'ok': False, 'code': 400, 'msg': '已是该组长，无需更换'}

        guanshi.yaoqingren = new_uid
        guanshi.save(update_fields=['yaoqingren'])

        if old_uid:
            try:
                old_zz = UserZuzhang.query.select_related('user').get(user__UserUID=old_uid)
                if (old_zz.yaoqing_zongshu or 0) > 0:
                    UserZuzhang.query.filter(pk=old_zz.pk).update(
                        yaoqing_zongshu=F('yaoqing_zongshu') - 1
                    )
            except UserZuzhang.DoesNotExist:
                pass
        UserZuzhang.query.filter(pk=zuzhang.pk).update(
            yaoqing_zongshu=F('yaoqing_zongshu') + 1
        )

        quota.used_count = int(quota.used_count or 0) + 1
        quota.save(update_fields=['used_count', 'UpdateTime'])

        GuanshiChangeLeaderLog.objects.create(
            club_id=club_id,
            guanshi_uid=user.UserUID,
            guanshi_name=_guanshi_display_name(user)[:50],
            old_zuzhang_uid=old_uid or '',
            new_zuzhang_uid=new_uid,
            new_invite_code=invite_code[:40],
            source=source or 'miniapp',
            operator=op[:64],
        )

    logger.info(
        'guanshi_change_leader ok club=%s gs=%s %s -> %s source=%s',
        club_id, user.UserUID, old_uid, new_uid, source,
    )
    return {
        'ok': True,
        'code': 200,
        'msg': '更换组长成功',
        'data': {
            'current_zuzhang': _zuzhang_brief(new_uid),
            'quota': quota_payload(quota),
            'old_zuzhang_uid': old_uid or '',
            'new_zuzhang_uid': new_uid,
        },
    }


def set_total_quota(club_id, guanshi_uid, total_quota):
    """后台设置总次数（不得小于已用次数）。"""
    try:
        total = int(total_quota)
    except (TypeError, ValueError):
        return {'ok': False, 'code': 400, 'msg': '总次数须为整数'}
    if total < 0:
        return {'ok': False, 'code': 400, 'msg': '总次数不能为负数'}

    quota = get_or_create_quota(club_id, guanshi_uid)
    if total < int(quota.used_count or 0):
        return {
            'ok': False,
            'code': 400,
            'msg': f'总次数不能小于已用次数（已用 {quota.used_count}）',
        }
    quota.total_quota = total
    quota.save(update_fields=['total_quota', 'UpdateTime'])
    return {'ok': True, 'code': 0, 'msg': '已更新', 'data': quota_payload(quota)}


def add_quota(club_id, guanshi_uid, add_n):
    """后台追加次数（增加 total_quota）。"""
    try:
        n = int(add_n)
    except (TypeError, ValueError):
        return {'ok': False, 'code': 400, 'msg': '追加次数须为整数'}
    if n <= 0:
        return {'ok': False, 'code': 400, 'msg': '追加次数须大于 0'}
    quota = get_or_create_quota(club_id, guanshi_uid)
    quota.total_quota = int(quota.total_quota or 0) + n
    quota.save(update_fields=['total_quota', 'UpdateTime'])
    return {'ok': True, 'code': 0, 'msg': '已追加', 'data': quota_payload(quota)}


def list_change_logs(club_id, guanshi_uid, page=1, page_size=20):
    qs = (
        GuanshiChangeLeaderLog.objects
        .filter(club_id=club_id, guanshi_uid=guanshi_uid)
        .order_by('-CreateTime', '-id')
    )
    total = qs.count()
    try:
        page = max(1, int(page))
    except (TypeError, ValueError):
        page = 1
    try:
        page_size = min(100, max(1, int(page_size)))
    except (TypeError, ValueError):
        page_size = 20
    start = (page - 1) * page_size
    rows = []
    for row in qs[start:start + page_size]:
        rows.append({
            'id': row.id,
            'old_zuzhang_uid': row.old_zuzhang_uid,
            'new_zuzhang_uid': row.new_zuzhang_uid,
            'new_invite_code': row.new_invite_code,
            'source': row.source,
            'operator': row.operator,
            'created_at': row.CreateTime.isoformat() if row.CreateTime else None,
        })
    return {
        'list': rows,
        'total': total,
        'page': page,
        'page_size': page_size,
    }
