import requests
import logging
import traceback
import copy
import urllib3
import time
from enum import Enum
from fastapi import HTTPException, status

from .config import decode_jwt_token

# 禁用 urllib3 的 InsecureRequestWarning 警告
# 这样可以避免在使用自定义 HTTPS 地址（可能没有有效证书）时出现警告信息
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


class CredentialTypeEnum(str, Enum):
    """凭证类型枚举，与后端API保持一致"""
    USERNAME = "username"
    EMAIL = "email"
    PHONE = "phone"
    WECHAT_OPENID = "wechat_openid"


class ConnectSkyplatformIam(object):
    _instance = None
    _initialized = False

    def __new__(cls, config=None, logger_name="skyplatform_iam", log_level=logging.INFO):
        """
        单例模式实现
        确保整个应用中只有一个ConnectSkyplatformIam实例
        """
        if cls._instance is None:
            cls._instance = super(ConnectSkyplatformIam, cls).__new__(cls)
        return cls._instance

    def __init__(self, config=None, logger_name="skyplatform_iam", log_level=logging.INFO):
        """
        初始化SkyplatformIAM连接器

        参数:
        - config: AuthConfig配置对象，如果为None则从环境变量读取
        - logger_name: 日志记录器名称
        - log_level: 日志级别
        """
        # 防止重复初始化
        if self._initialized:
            return

        # 必须传入config参数，不再支持从环境变量读取
        if config is None:
            raise ValueError("必须传入AuthConfig配置对象，不再支持从环境变量读取配置")

        # 保存配置对象，用于日志控制
        self.config = config

        # 根据配置设置日志级别
        if hasattr(config, 'enable_sdk_logging') and not config.enable_sdk_logging:
            # 禁用SDK日志时，设置为WARNING级别，只显示警告和错误
            effective_log_level = logging.WARNING
        else:
            # 启用SDK日志时，使用传入的日志级别
            effective_log_level = log_level

        # 配置日志记录器
        self.logger = logging.getLogger(logger_name)
        if not self.logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
            )
            handler.setFormatter(formatter)
            self.logger.addHandler(handler)
            self.logger.setLevel(effective_log_level)

        self.skyplatform_iam_host = config.skyplatform_iam_host
        self.server_name = config.server_name
        self.access_key = config.access_key
        self.machine_token = config.machine_token
        self._machine_token_exp = None
        self._machine_token_last_fetch = None
        self._default_machine_token_ttl = 7200
        
        if hasattr(config, 'enable_sdk_logging') and config.enable_sdk_logging:
            self.logger.info("使用传入的AuthConfig配置")

        # 验证必要的配置
        if not self.skyplatform_iam_host:
            self.logger.warning("SKYPLATFORM_IAM_HOST 配置未设置")
        if not self.server_name:
            self.logger.warning("SKYPLATFORM_SERVER_NAME 配置未设置")
        if not self.access_key:
            self.logger.warning("SKYPLATFORM_ACCESS_KEY 配置未设置")

        if hasattr(config, 'enable_sdk_logging') and config.enable_sdk_logging:
            self.logger.info(
                f"初始化SkyplatformIAM连接器 - Host: {self.skyplatform_iam_host}, Server: {self._mask_sensitive(self.server_name)}")

        self.service_credential_headers = {
            "Content-Type": "application/json",
            "SERVER-AK": self.server_name,
            "SERVER-SK": self.access_key
        }

        try:
            self.ensure_machine_token()
        except Exception:
            pass

        # 标记为已初始化
        self._initialized = True

    def _build_headers(self):
        self.ensure_machine_token()
        h = {
            "Content-Type": "application/json",
        }
        if self.machine_token:
            h["MACHINE-TOKEN"] = self.machine_token
        return h

    def _build_service_credential_headers(self):
        return self.service_credential_headers.copy()

    def _update_machine_token(self, token):
        self.machine_token = token
        self._machine_token_last_fetch = time.time()
        try:
            payload = decode_jwt_token(token) or {}
            self._machine_token_exp = payload.get("exp")
        except Exception:
            self._machine_token_exp = None
        try:
            if hasattr(self, "config"):
                self.config.machine_token = token
        except Exception:
            pass

    def _is_machine_token_valid(self, margin=300):
        if not self.machine_token:
            return False
        if self._machine_token_exp:
            return (time.time() + margin) < float(self._machine_token_exp)
        if self._machine_token_last_fetch:
            return (time.time() - self._machine_token_last_fetch) < (self._default_machine_token_ttl - margin)
        return True

    def reload_config(self, config):
        """
        重新加载配置
        用于在运行时更新配置

        参数:
        - config: AuthConfig配置对象
        """
        if config is None:
            raise ValueError("必须传入AuthConfig配置对象")

        self.logger.info("重新加载配置")

        # 更新配置
        self.skyplatform_iam_host = config.skyplatform_iam_host
        self.server_name = config.server_name
        self.access_key = config.access_key

        # 验证必要的配置
        if not self.skyplatform_iam_host:
            self.logger.warning("SKYPLATFORM_IAM_HOST 配置未设置")
        if not self.server_name:
            self.logger.warning("SKYPLATFORM_SERVER_NAME 配置未设置")
        if not self.access_key:
            self.logger.warning("SKYPLATFORM_ACCESS_KEY 配置未设置")

        # 更新headers和body
        self.service_credential_headers = {
            "Content-Type": "application/json",
            "SERVER-AK": self.server_name,
            "SERVER-SK": self.access_key
        }
        self.ensure_machine_token()

        self.body = {
            "machine_token": self.machine_token,
        }

        self.logger.info(
            f"配置重新加载完成 - Host: {self.skyplatform_iam_host}, Server: {self._mask_sensitive(self.server_name)}")

    def ensure_machine_token(self):
        """
        确保SDK持有machine_token；若为空则尝试向IAM获取
        """
        try:
            if self._is_machine_token_valid():
                return self.machine_token
            token = self._fetch_machine_token()
            if token:
                self._update_machine_token(token)
                return token
        except Exception as e:
            self.logger.warning(f"[ensure_machine_token] 自动获取machine_token失败: {str(e)}")
        return self.machine_token

    def _fetch_machine_token(self):
        """
        通过服务凭据请求IAM下发machine_token，兼容多种可能的接口命名
        """
        method_name = "fetch_machine_token"
        endpoints = [
            "/api/v2/service/get_machine_token",
            "/api/v2/service/machine_token",
        ]
        body = {
            "server_name": self.server_name,
            "access_key": self.access_key,
        }
        for uri in endpoints:
            try:
                url = self.skyplatform_iam_host + uri
                service_headers = self._build_service_credential_headers()
                self._log_request(method_name, url, service_headers, body)
                response = requests.post(
                    url=url,
                    headers=service_headers,
                    json=body,
                    verify=False
                )
                self._log_response(method_name, response)
                if response.status_code == 200:
                    data = {}
                    try:
                        data = response.json()
                    except Exception:
                        data = {}
                    token = None
                    # 兼容数据结构：data字段或顶层字段
                    container = data.get("data", data)
                    if isinstance(container, dict):
                        token = container.get("machine_token") or container.get("machine_access_token")
                    elif isinstance(container, str):
                        token = container
                    if token:
                        self.logger.info(f"[{method_name}] 获取machine_token成功")
                        self._update_machine_token(token)
                        return token
            except Exception as e:
                self.logger.warning(f"[{method_name}] 尝试 {uri} 失败: {str(e)}")
        self.logger.warning(f"[{method_name}] 无法自动获取machine_token")
        return None
    def _mask_sensitive(self, value, mask_char="*", show_chars=4):
        """
        脱敏处理敏感信息

        参数:
        - value: 要脱敏的值
        - mask_char: 脱敏字符
        - show_chars: 显示的字符数量

        返回: 脱敏后的字符串
        """
        if not value or not isinstance(value, str):
            return str(value) if value else "None"

        if len(value) <= show_chars:
            return mask_char * len(value)

        return value[:show_chars] + mask_char * (len(value) - show_chars)

    def _sanitize_log_data(self, data):
        """
        清理日志数据，脱敏敏感信息

        参数:
        - data: 要清理的数据（字典或其他类型）

        返回: 清理后的数据
        """
        if not isinstance(data, dict):
            return data

        # 需要脱敏的字段列表
        sensitive_fields = [
            'password', 'access_key', 'token', 'refresh_token',
            'SERVER-SK', 'new_password', 'server_sk'
        ]

        sanitized = copy.deepcopy(data)

        for key, value in sanitized.items():
            if key.lower() in [field.lower() for field in sensitive_fields]:
                sanitized[key] = self._mask_sensitive(str(value))
            elif isinstance(value, dict):
                sanitized[key] = self._sanitize_log_data(value)

        return sanitized

    def _log_request(self, method_name, url, headers, body):
        """记录请求信息"""
        # 只有在启用SDK日志时才输出详细的请求信息
        if hasattr(self, 'config') and hasattr(self.config, 'enable_sdk_logging') and self.config.enable_sdk_logging:
            sanitized_headers = self._sanitize_log_data(headers)
            sanitized_body = self._sanitize_log_data(body)

            self.logger.info(f"[{method_name}] 发送请求 - URL: {url}")
            self.logger.info(f"[{method_name}] 请求头: {sanitized_headers}")
            self.logger.info(f"[{method_name}] 请求体: {sanitized_body}")

    def _log_response(self, method_name, response):
        """记录响应信息"""
        # 只有在启用SDK日志时才输出详细的响应信息
        if hasattr(self, 'config') and hasattr(self.config, 'enable_sdk_logging') and self.config.enable_sdk_logging:
            try:
                response_data = response.json() if response.content else {}
                sanitized_response = self._sanitize_log_data(response_data)
                self.logger.info(f"[{method_name}] 响应状态码: {response.status_code}")
                self.logger.info(f"[{method_name}] 响应内容: {sanitized_response}")
            except Exception as e:
                self.logger.info(f"[{method_name}] 响应状态码: {response.status_code}")
                self.logger.info(f"[{method_name}] 响应内容解析失败: {str(e)}")

    def register(self, cred_type=None, cred_value=None, password=None, nickname=None, avatar_url=None,
                 username=None, phone=None):
        """
        注册用户时，同步至iam

        新参数格式（推荐使用）:
        - cred_type: 凭证类型 (CredentialTypeEnum: username, email, phone, wechat_openid)
        - cred_value: 凭证值
        - password: 用户密码（可选）
        - nickname: 用户昵称（可选）
        - avatar_url: 头像URL（可选）

        旧参数格式（向后兼容）:
        - username: 要注册的用户名
        - phone: 手机号码（可选）
        - password: 用户密码
        - nickname: 用户昵称（可选）

        返回:
        - 成功: 返回包含用户信息的字典
        - 失败: 返回False
        """
        method_name = "register"
        self.logger.info(
            f"[{method_name}] 开始用户注册 - cred_type: {cred_type}, cred_value: {self._mask_sensitive(str(cred_value))}")

        try:
            self.ensure_machine_token()
            # 参数映射：支持旧的调用方式
            if cred_type is None and cred_value is None:
                if username:
                    cred_type = CredentialTypeEnum.USERNAME
                    cred_value = username
                    self.logger.debug(f"[{method_name}] 使用旧参数格式 - username: {self._mask_sensitive(username)}")
                elif phone:
                    cred_type = CredentialTypeEnum.PHONE
                    cred_value = phone
                    self.logger.debug(f"[{method_name}] 使用旧参数格式 - phone: {self._mask_sensitive(phone)}")
                else:
                    raise ValueError("必须提供 cred_type+cred_value 或 username/phone")

            # 验证凭证类型
            if isinstance(cred_type, str):
                cred_type = CredentialTypeEnum(cred_type)

            body = {
                "cred_type": cred_type.value,
                "cred_value": cred_value
            }

            # 添加可选参数
            if password:
                body["password"] = password
            if nickname:
                body["nickname"] = nickname
            if avatar_url:
                body["avatar_url"] = avatar_url

            uri = "/api/v2/service/register"
            url = self.skyplatform_iam_host + uri

            # 记录请求信息
            self._log_request(method_name, url, self._build_headers(), body)

            response = requests.post(
                url=url,
                headers=self._build_headers(),
                json=body,
                verify=False
            )

            # 记录响应信息
            self._log_response(method_name, response)

            if response.status_code == 200:
                result = response.json()
                if result.get("success"):
                    self.logger.info(f"[{method_name}] 用户注册成功")
                    return result.get("data")
                else:
                    self.logger.warning(f"[{method_name}] 用户注册失败 - 响应: {result}")
            else:
                self.logger.warning(f"[{method_name}] 用户注册失败 - 状态码: {response.status_code}")

            return False
        except Exception as e:
            self.logger.error(f"[{method_name}] 注册请求异常: {str(e)}")
            self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
            return False

    def login_with_password(self, cred_type=None, cred_value=None, password=None, ip_address=None, user_agent=None,
                            username=None):
        """
        账号密码登陆时，同步至iam，由iam签发token

        新参数格式（推荐使用）:
        - cred_type: 凭证类型 (CredentialTypeEnum: username, email, phone, wechat_openid)
        - cred_value: 凭证值
        - password: 用户密码
        - ip_address: IP地址（可选）
        - user_agent: 用户代理（可选）

        旧参数格式（向后兼容）:
        - username: 用户名
        - password: 用户密码
        """
        method_name = "login_with_password"
        self.logger.info(
            f"[{method_name}] 开始密码登录 - cred_type: {cred_type}, cred_value: {self._mask_sensitive(str(cred_value))}")

        try:
            # 参数映射：支持旧的调用方式
            if cred_type is None and cred_value is None:
                if username:
                    cred_type = CredentialTypeEnum.USERNAME
                    cred_value = username
                    self.logger.debug(f"[{method_name}] 使用旧参数格式 - username: {self._mask_sensitive(username)}")
                else:
                    raise ValueError("必须提供 cred_type+cred_value 或 username")

            # 验证凭证类型
            if isinstance(cred_type, str):
                cred_type = CredentialTypeEnum(cred_type)

            body = {
                "cred_type": cred_type.value,
                "cred_value": cred_value,
                "password": password
            }

            # 添加可选参数
            if ip_address:
                body["ip_address"] = ip_address
            if user_agent:
                body["user_agent"] = user_agent

            uri = "/api/v2/service/login"
            url = self.skyplatform_iam_host + uri

            # 记录请求信息
            self._log_request(method_name, url, self._build_headers(), body)

            response = requests.post(
                url=url,
                headers=self._build_headers(),
                json=body,
                verify=False
            )

            # 记录响应信息
            self._log_response(method_name, response)

            if response.status_code == 200:
                self.logger.info(f"[{method_name}] 密码登录成功")
                data = response.json()["data"]
                access_token = data["access_token"]
                payload = decode_jwt_token(access_token)
                self._update_machine_token(payload["machine_access_token"])

                return response
            else:
                self.logger.warning(f"[{method_name}] 密码登录失败 - 状态码: {response.status_code}")

            return False
        except Exception as e:
            self.logger.error(f"[{method_name}] 密码登录请求异常: {str(e)}")
            self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
            return False


    def logout(self, token):
        """
        用户登出
        server_name: 服务名称
        username: 用户名
        """
        method_name = "logout"
        self.logger.info(f"[{method_name}] 开始用户登出 - token: {self._mask_sensitive(token)}")

        try:
            self.ensure_machine_token()
            body = {
                "token": token
            }
            uri = "/api/v2/service/logout"
            url = self.skyplatform_iam_host + uri

            # 记录请求信息
            self._log_request(method_name, url, self._build_headers(), body)

            response = requests.post(
                url=url,
                headers=self._build_headers(),
                json=body,
                verify=False
            )

            # 记录响应信息
            self._log_response(method_name, response)

            if response.status_code == 200:
                self.logger.info(f"[{method_name}] 用户登出成功")
                return True
            else:
                self.logger.warning(f"[{method_name}] 用户登出失败 - 状态码: {response.status_code}")

            return False
        except Exception as e:
            self.logger.error(f"[{method_name}] 登出请求异常: {str(e)}")
            self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
            return False

    def verify_token(self, token, api, method, server_ak="", server_sk="", machine_token=""):
        """
        请求iam进行鉴权
        server_name: 服务名称
        token: 用户token
        api: 当前访问的API路径

        返回:
        - 成功且有权限: 返回用户信息字典
        - 成功但无权限: 抛出403异常
        - token无效或其他错误: 返回None
        """
        method_name = "verify_token"
        self.logger.info(
            f"[{method_name}] 开始token验证 - api: {api}, method: {method}, token: {self._mask_sensitive(token)}")

        try:
            self.ensure_machine_token()
            body = {
                "machine_token": machine_token if machine_token else self.machine_token,
                "token": token,
                "api": api,
                "method": method,
                "server_ak": server_ak,
                "server_sk": server_sk,
            }
            uri = "/api/v2/service/verify"

            # 检查skyplatform_iam_host是否为None
            if self.skyplatform_iam_host is None:
                raise ValueError("SKYPLATFORM_IAM_HOST 配置未设置或为空，请确保传入正确的AuthConfig对象")

            url = self.skyplatform_iam_host + uri

            # 记录请求信息
            self._log_request(method_name, url, self._build_headers(), body)

            response = requests.post(
                url=url,
                headers=self._build_headers(),
                json=body,
                verify=False
            )

            # 记录响应信息
            self._log_response(method_name, response)

            if response.status_code == 200:
                result = response.json()
                # 检查响应格式
                if result.get("success") and result.get("valid"):
                    if result.get("has_permission"):
                        # 有权限时返回用户信息
                        user_info = {
                            "user_id": result.get("user_id"),
                            "username": result.get("username"),
                            "session_id": result.get("session_id"),
                            "space": result.get("space"),
                            "is_whitelist": result.get("is_whitelist", False)
                        }
                        self.logger.info(
                            f"[{method_name}] token验证成功，用户有权限 - user_id: {user_info.get('user_id')}")
                        return user_info
                    else:
                        # token有效但无权限，抛出403异常
                        self.logger.warning(f"[{method_name}] token有效但用户无权限访问API: {api}")
                        raise HTTPException(
                            status_code=status.HTTP_403_FORBIDDEN,
                            detail=result.get("message", "用户无权限访问此API")
                        )
                else:
                    self.logger.warning(
                        f"[{method_name}] token验证失败 - success: {result.get('success')}, valid: {result.get('valid')}")

            elif response.status_code == 403:
                result = response.json()
                # 处理403响应
                self.logger.warning(f"[{method_name}] 收到403响应 - {result.get('message', '用户无权限访问此API')}")
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail=result.get("message", "用户无权限访问此API")
                )
            else:
                self.logger.warning(f"[{method_name}] token验证失败 - 状态码: {response.status_code}")

            return None
        except HTTPException:
            # 重新抛出HTTP异常
            raise
        except Exception as e:
            self.logger.error(f"[{method_name}] Token验证异常: {str(e)}")
            self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
            return None


    def refresh_token(self, refresh_token):
        """
        机机接口：刷新用户令牌

        参数:
        - refresh_token: 刷新令牌

        返回: response对象或False
        """
        method_name = "refresh_token"
        self.logger.info(f"[{method_name}] 开始刷新令牌 - refresh_token: {self._mask_sensitive(refresh_token)}")

        try:
            self.ensure_machine_token()
            body = {
                "refresh_token": refresh_token
            }
            uri = "/api/v2/service/refresh_token"
            url = self.skyplatform_iam_host + uri

            # 记录请求信息
            self._log_request(method_name, url, self._build_headers(), body)

            response = requests.post(
                url=url,
                headers=self._build_headers(),
                json=body,
                verify=False
            )

            # 记录响应信息
            self._log_response(method_name, response)

            if response.status_code == 200:
                self.logger.info(f"[{method_name}] 令牌刷新成功")
                data = response.json()["data"]
                access_token = data["access_token"]
                payload = decode_jwt_token(access_token)
                self._update_machine_token(payload["machine_access_token"])

                return response
            else:
                self.logger.warning(f"[{method_name}] 令牌刷新失败 - 状态码: {response.status_code}")

            return False
        except Exception as e:
            self.logger.error(f"[{method_name}] 刷新令牌请求异常: {str(e)}")
            self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
            return False


    def add_custom_config(self, user_id, config_name, config_value=None):
        """
        机机接口：添加用户自定义配置

        为指定用户添加或更新自定义属性配置。

        参数:
        - user_id: 用户ID
        - config_name: 配置项名称
        - config_value: 配置项值（可选）

        返回:
        - 成功: 返回响应对象
        - 失败: 返回False
        """
        method_name = "add_custom_config"
        self.logger.info(f"[{method_name}] 开始添加用户自定义配置 - user_id: {user_id}, config_name: {config_name}")

        try:
            self.ensure_machine_token()
            body = {
                "user_id": user_id,
                "config_name": config_name,
                "config_value": config_value
            }

            # 添加可选参数
            # if config_value is not None:
            #     body["config_value"] = config_value

            uri = "/api/v2/service/add_custom_config"
            url = self.skyplatform_iam_host + uri

            # 记录请求信息
            self._log_request(method_name, url, self._build_headers(), body)

            response = requests.post(
                url=url,
                headers=self._build_headers(),
                json=body,
                verify=False
            )

            # 记录响应信息
            self._log_response(method_name, response)

            if response.status_code == 200:
                self.logger.info(f"[{method_name}] 添加用户自定义配置成功")
                return response
            else:
                self.logger.warning(f"[{method_name}] 添加用户自定义配置失败 - 状态码: {response.status_code}")

            return False
        except Exception as e:
            self.logger.error(f"[{method_name}] 添加用户自定义配置请求异常: {str(e)}")
            self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
            return False

    def get_custom_configs(self, user_id):
        """
        机机接口：获取用户自定义配置

        获取指定用户的所有自定义属性配置。

        参数:
        - user_id: 用户ID

        返回:
        - 成功: 返回响应对象
        - 失败: 返回False
        """
        method_name = "get_custom_configs"
        self.logger.info(f"[{method_name}] 开始获取用户自定义配置 - user_id: {user_id}")

        try:
            self.ensure_machine_token()
            body = {
                "user_id": user_id
            }

            uri = "/api/v2/service/get_custom_configs"
            url = self.skyplatform_iam_host + uri

            # 记录请求信息
            self._log_request(method_name, url, self._build_headers(), body)

            response = requests.post(
                url=url,
                headers=self._build_headers(),
                json=body,
                verify=False
            )

            # 记录响应信息
            self._log_response(method_name, response)

            if response.status_code == 200:
                self.logger.info(f"[{method_name}] 获取用户自定义配置成功")
                return response
            else:
                self.logger.warning(f"[{method_name}] 获取用户自定义配置失败 - 状态码: {response.status_code}")

            return False
        except Exception as e:
            self.logger.error(f"[{method_name}] 获取用户自定义配置请求异常: {str(e)}")
            self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
            return False

    def delete_custom_config(self, user_id, config_name):
        """
        机机接口：删除用户自定义配置

        删除指定用户的指定自定义属性配置。

        参数:
        - user_id: 用户ID
        - config_name: 配置项名称

        返回:
        - 成功: 返回响应对象
        - 失败: 返回False
        """
        method_name = "delete_custom_config"
        self.logger.info(f"[{method_name}] 开始删除用户自定义配置 - user_id: {user_id}, config_name: {config_name}")

        try:
            self.ensure_machine_token()
            body = {
                "user_id": user_id,
                "config_name": config_name
            }

            uri = "/api/v2/service/delete_custom_config"
            url = self.skyplatform_iam_host + uri

            # 记录请求信息
            self._log_request(method_name, url, self._build_headers(), body)

            response = requests.post(
                url=url,
                headers=self._build_headers(),
                json=body,
                verify=False
            )

            # 记录响应信息
            self._log_response(method_name, response)

            if response.status_code == 200:
                self.logger.info(f"[{method_name}] 删除用户自定义配置成功")
                return response
            else:
                self.logger.warning(f"[{method_name}] 删除用户自定义配置失败 - 状态码: {response.status_code}")

            return False
        except Exception as e:
            self.logger.error(f"[{method_name}] 删除用户自定义配置请求异常: {str(e)}")
            self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
            return False


    def get_space_users(self, search=None, status=None, cred_type=None, user_id=None,
                        page=1, per_page=20, sort_by="create_time", sort_order="desc"):
        """
        机机接口：获取空间用户列表

        返回服务所属 Space 的用户列表，支持分页与搜索。

        参数:
        - search: 关键词搜索（可选）
        - status: 用户状态过滤（可选，如 "active"）
        - cred_type: 凭证类型过滤（可选，CredentialTypeEnum: username, email, phone, wechat_openid）
        - user_id: 用户ID过滤（可选）
        - page: 页码，默认1
        - per_page: 每页数量，默认20，最大100
        - sort_by: 排序字段，默认 "create_time"
        - sort_order: 排序方向，默认 "desc"

        返回:
        - 成功: 返回响应对象
        - 失败: 返回False
        """
        method_name = "get_space_users"
        self.logger.info(
            f"[{method_name}] 开始获取空间用户列表 - search: {search}, page: {page}, per_page: {per_page}")

        try:
            self.ensure_machine_token()

            # 验证凭证类型
            if cred_type is not None and isinstance(cred_type, str):
                cred_type = CredentialTypeEnum(cred_type)

            body = {
                "page": page,
                "per_page": min(per_page, 100),
                "sort_by": sort_by,
                "sort_order": sort_order
            }

            # 添加可选参数
            if search is not None:
                body["search"] = search
            if status is not None:
                body["status"] = status if isinstance(status, str) else status.value
            if cred_type is not None:
                body["cred_type"] = cred_type.value if hasattr(cred_type, 'value') else cred_type
            if user_id is not None:
                body["user_id"] = user_id

            uri = "/api/v2/service/space_users/list"
            url = self.skyplatform_iam_host + uri

            # 记录请求信息
            self._log_request(method_name, url, self._build_headers(), body)

            response = requests.post(
                url=url,
                headers=self._build_headers(),
                json=body,
                verify=False
            )

            # 记录响应信息
            self._log_response(method_name, response)

            if response.status_code == 200:
                self.logger.info(f"[{method_name}] 获取空间用户列表成功")
                return response
            else:
                self.logger.warning(f"[{method_name}] 获取空间用户列表失败 - 状态码: {response.status_code}")

            return False
        except Exception as e:
            self.logger.error(f"[{method_name}] 获取空间用户列表请求异常: {str(e)}")
            self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
            return False
