"""角色/后台客服按俱乐部隔离（权限码全局共用，角色实体按 club 分开）。"""
from django.db.models import Q

from gvsdsdk.models import Role, UserRole

from jituan.constants import CLUB_ID_DEFAULT, DATA_SCOPE_ALL
from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope


def _global_role_q():
    """集团全局角色：club_id 为空或 NULL。"""
    return Q(ClubID='') | Q(ClubID__isnull=True)


def resolve_role_club_id(request, explicit=None):
    """
    创建/筛选角色时使用的俱乐部。
    单俱乐部视图：强制当前顶栏俱乐部，忽略跨店 target_club_id。
    集团汇总视图：可显式指定；未指定则为全局（club_id 空）。
    """
    scope = resolve_club_scope(request)
    if scope != DATA_SCOPE_ALL:
        return resolve_club_id_from_request(request)
    if explicit:
        return (explicit or '').strip()
    return ''


def filter_roles_for_request(request):
    """
    子公司视图：优先本俱乐部角色；本俱乐部尚无角色时仅回落集团全局角色。
    绝不混入其他俱乐部角色。
    集团汇总视图：全部角色（含各俱乐部 + 全局）。
    """
    qs = Role.objects.filter(RoleStatus=1)
    scope = resolve_club_scope(request)
    if scope == DATA_SCOPE_ALL:
        return qs
    club_id = resolve_club_id_from_request(request)
    club_qs = qs.filter(ClubID=club_id)
    if club_qs.exists():
        return club_qs
    return qs.filter(_global_role_q())


def role_visible_in_scope(role_club_id, request):
    """列表展示用：单俱乐部视图只允许本俱乐部或全局（无本俱乐部角色时由调用方决定）。"""
    scope = resolve_club_scope(request)
    if scope == DATA_SCOPE_ALL:
        return True
    curr = (resolve_club_id_from_request(request) or '').strip()
    cid = (role_club_id or '').strip()
    return cid == '' or cid == curr


def filter_kefu_users_by_admin_scope(qs, request):
    """
    后台用户列表：按任职俱乐部过滤，而非仅 User.ClubID。
    同一账号有多俱乐部任职时，在任一已分配俱乐部视图下均可见。
    """
    from jituan.models import AdminAssignment

    scope = resolve_club_scope(request)
    if scope == DATA_SCOPE_ALL:
        return qs
    club_id = resolve_club_id_from_request(request)
    assigned_uids = list(
        AdminAssignment.query.filter(status=1, club_id=club_id).values_list('yonghuid', flat=True)
    )
    if club_id == CLUB_ID_DEFAULT:
        return qs.filter(
            Q(UserUID__in=assigned_uids)
            | Q(ClubID=club_id)
            | Q(ClubID__isnull=True)
            | Q(ClubID='')
        )
    return qs.filter(Q(UserUID__in=assigned_uids) | Q(ClubID=club_id))


def filter_kefu_users_qs(qs, request):
    """后台客服账号列表按 User.ClubID 过滤（角色统计等场景）。"""
    scope = resolve_club_scope(request)
    if scope == DATA_SCOPE_ALL:
        return qs
    club_id = resolve_club_id_from_request(request)
    if club_id == CLUB_ID_DEFAULT:
        return qs.filter(Q(ClubID=club_id) | Q(ClubID__isnull=True) | Q(ClubID=''))
    return qs.filter(ClubID=club_id)


def count_role_users_in_scope(role, request, kefu_user_uuids):
    """统计角色下客服数（仅计当前数据范围内的客服）。"""
    from users.business_models import User

    uuids = list(
        UserRole.objects.filter(RoleUUID=role.RoleUUID)
        .values_list('UserUUID', flat=True)
    )
    if not uuids:
        return 0
    qs = User.objects.filter(UserUUID__in=uuids, KefuProfile__isnull=False)
    qs = filter_kefu_users_qs(qs, request)
    if kefu_user_uuids is not None:
        qs = qs.filter(UserUUID__in=kefu_user_uuids)
    return qs.count()


def role_name_exists(role_name, club_id):
    return Role.objects.filter(RoleName=role_name, ClubID=club_id or '').exists()


def resolve_role_by_name(role_name, club_id=None):
    """按角色名解析 Role；优先匹配指定俱乐部，其次全局角色（club_id 为空）。"""
    name = (role_name or '').strip()
    if not name:
        return None
    qs = Role.objects.filter(RoleName=name, RoleStatus=1)
    cid = (club_id or '').strip()
    if cid:
        hit = qs.filter(ClubID=cid).first()
        if hit:
            return hit
    return qs.filter(_global_role_q()).first()


def role_uuid_bytes(role_uuid):
    """RoleUUID 统一转 bytes（兼容 UUIDObj / bytes / str）。"""
    from gvsdsdk.model_utils import UUIDObj
    if isinstance(role_uuid, bytes):
        return role_uuid
    return UUIDObj(role_uuid).bytes


def resolve_roles_for_binding(role_names, club_id=None):
    """
    按角色名解析并去重；任一角色在当前俱乐部下找不到则整体失败。
    返回 (roles, missing_names)。
    """
    resolved = []
    missing = []
    seen_bytes = set()
    for raw in role_names or []:
        name = (raw or '').strip()
        if not name:
            continue
        role = resolve_role_by_name(name, club_id)
        if not role:
            missing.append(name)
            continue
        key = role_uuid_bytes(role.RoleUUID)
        if key in seen_bytes:
            continue
        seen_bytes.add(key)
        resolved.append(role)
    return resolved, missing


def filter_role_uuids_for_club_scope(role_uuids, club_id, scope, allowed_club_ids=None):
    """
    按当前俱乐部上下文过滤 UserRole 绑定的 RoleUUID。
    SINGLE_CLUB：本俱乐部角色 + 全局角色（ClubID 空/NULL）。
    ALL_CLUBS：已授权各俱乐部角色 + 全局角色。
    使用 bytes 比对（兼容 UUIDObj），避免 ORM __in 在 BINARY(16) 上匹配失败。
    """
    if not role_uuids:
        return []
    wanted = {role_uuid_bytes(u) for u in role_uuids}

    matched = []
    for ruuid, rcid_raw in Role.objects.filter(RoleStatus=1).values_list('RoleUUID', 'ClubID'):
        if role_uuid_bytes(ruuid) not in wanted:
            continue
        rcid = (rcid_raw or '').strip()
        if scope == DATA_SCOPE_ALL:
            club_ids = {c for c in (allowed_club_ids or []) if c}
            if rcid == '' or rcid in club_ids:
                matched.append(ruuid)
        else:
            cid = (club_id or CLUB_ID_DEFAULT).strip()
            if rcid == cid or rcid == '':
                matched.append(ruuid)
    return matched


def resolve_permission_codes_for_club(user, club_id, allowed_club_ids=None, scope=None):
    """当前俱乐部上下文下的 gvsdsdk 权限码（与 verify_kefu_permission / 菜单共用）。"""
    from jituan.constants import DATA_SCOPE_SINGLE
    from gvsdsdk.models import Permission as SdkPermission, RolePermission as SdkRolePermission, UserRole as SdkUserRole

    eff_scope = scope or DATA_SCOPE_SINGLE
    role_uuids = list(SdkUserRole.objects.filter(
        UserUUID=user.UserUUID,
    ).values_list('RoleUUID', flat=True))
    role_uuids = filter_role_uuids_for_club_scope(
        role_uuids, club_id, eff_scope, allowed_club_ids,
    )
    if not role_uuids:
        return []
    perm_uuids = SdkRolePermission.objects.filter(
        RoleUUID__in=role_uuids,
    ).values_list('PermUUID', flat=True)
    return list(
        SdkPermission.objects.filter(
            PermUUID__in=perm_uuids, PermStatus=1,
        ).values_list('PermCode', flat=True).distinct()
    )


def resolve_effective_permission_codes(user, club_id, scope, allowed_club_ids=None):
    """
    菜单与各业务接口统一权限码：当前俱乐部 gvsdsdk 角色 + legacy 合并。
    """
    from backend.utils import _legacy_backend_role_permissions

    codes = list(resolve_permission_codes_for_club(
        user, club_id, allowed_club_ids, scope=scope,
    ))
    legacy_codes, _ = _legacy_backend_role_permissions(getattr(user, 'Phone', ''))
    if legacy_codes:
        codes = list(dict.fromkeys(codes + list(legacy_codes)))
    return codes


def describe_roles_in_scope(user, club_id, scope, allowed_club_ids=None):
    """诊断：当前俱乐部上下文中生效的角色与权限码。"""
    from gvsdsdk.models import Permission as SdkPermission, RolePermission as SdkRolePermission, UserRole as SdkUserRole

    all_bound = list(SdkUserRole.objects.filter(
        UserUUID=user.UserUUID,
    ).values_list('RoleUUID', flat=True))
    in_scope = filter_role_uuids_for_club_scope(
        all_bound, club_id, scope, allowed_club_ids,
    )
    rows = []
    for role in Role.objects.filter(RoleUUID__in=in_scope, RoleStatus=1):
        rcid = (getattr(role, 'ClubID', None) or '').strip() or '(全局)'
        perm_uuids = SdkRolePermission.objects.filter(
            RoleUUID=role.RoleUUID,
        ).values_list('PermUUID', flat=True)
        perm_codes = list(
            SdkPermission.objects.filter(
                PermUUID__in=perm_uuids, PermStatus=1,
            ).values_list('PermCode', flat=True)
        )
        rows.append({
            'role_name': role.RoleName,
            'club_id': rcid,
            'perm_codes': perm_codes,
        })
    return {
        'bound_role_count': len(all_bound),
        'in_scope_role_count': len(in_scope),
        'roles': rows,
    }


def user_bound_role_names(user, club_id=None, scope=None, allowed_club_ids=None):
    from backend.utils import _legacy_backend_role_permissions

    uuids = list(
        UserRole.objects.filter(UserUUID=user.UserUUID).values_list('RoleUUID', flat=True)
    )
    if club_id is not None and scope is not None:
        uuids = filter_role_uuids_for_club_scope(uuids, club_id, scope, allowed_club_ids)
    names = []
    if uuids:
        names = list(
            Role.objects.filter(RoleUUID__in=uuids, RoleStatus=1).values_list('RoleName', flat=True)
        )
    if club_id is None:
        _, legacy_names = _legacy_backend_role_permissions(getattr(user, 'Phone', ''))
        return sorted(set(names + legacy_names))
    return sorted(set(names))


def resolve_kefu_admin_user(yonghuid=None, phone=None):
    """定位后台客服 User；优先 yonghuid（同手机号多账号时必须用 ID）。"""
    from users.business_models import User

    uid = (yonghuid or '').strip()
    if uid:
        user = User.objects.filter(UserUID=uid, KefuProfile__isnull=False).first()
        if user:
            return user
    ph = (phone or '').strip()
    if not ph:
        return None
    return User.objects.filter(Phone=ph, KefuProfile__isnull=False).order_by('-UserCreateTime').first()
