import 'dart:async';

import 'package:flutter/foundation.dart' show debugPrint;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:networks_sdk/networks_sdk.dart';

import 'package:im_app/core/foundation/api_paths.dart';
import 'package:im_app/core/foundation/config.dart';
import 'package:im_app/core/foundation/constants.dart';
import 'package:im_app/core/foundation/device_info.dart';
import 'package:im_app/core/foundation/errors.dart';
import 'package:im_app/core/foundation/utils.dart';
import 'package:im_app/core/services/network_monitor.dart';
import 'package:im_app/core/services/socket_manager.dart';

// ── 网络状态监听 ──────────────────────────────────────────────────────────────

/// 网络状态监听 Provider（全局单例）
///
/// 基于 connectivity_plus 监听平台网络变化，
/// 作为公共服务供多个模块使用：
/// - SocketManager：网络变化时自动断连/重连 WebSocket
/// - HTTP 层：请求前检查网络可用性
/// - UI 层：显示网络状态提示
///
/// ## 使用
///
/// ```dart
/// // 查询当前状态
/// final isConnected = ref.read(networkMonitorProvider).isConnected;
///
/// // 监听状态变化
/// ref.listen(networkMonitorProvider, (prev, monitor) {
///   monitor.onStatusChanged.listen((isAvailable) {
///     // 处理网络变化
///   });
/// });
/// ```
final networkMonitorProvider = Provider<NetworkMonitor>((ref) {
  final monitor = NetworkMonitor(onLog: _makeLogger('Network'));

  ref.onDispose(() {
    monitor.dispose();
  });

  return monitor;
});

// ── Token 更新事件流 ─────────────────────────────────────────────────────────

/// Token 更新事件流
///
/// apiConfigProvider.onTokenUpdated → 推送新 token 到此流
/// socketManagerProvider → 监听此流 → 同步 token 到 WebSocket
/// onBeforeReconnect 中刷新 token 后调用 apiConfig.updateToken → tokenStream.add，
/// 需要同步传播到 socketManager.updateToken → socketClient._currentToken，
/// 确保随后的 _doConnect() 使用新 token。异步模式下 _doConnect 会在 stream
final _tokenUpdateStreamProvider = Provider<StreamController<String>>((ref) {
  final controller = StreamController<String>.broadcast(sync: true);
  ref.onDispose(controller.close);
  return controller;
});

// ── HTTP 基础设施 ─────────────────────────────────────────────────────────────

/// API 配置 Provider（全局单例）
///
/// 从 [AppConfig.apiBaseUrl]（config.json → --dart-define-from-file）读取 baseURL，
/// 注入到 Network SDK 作为所有 HTTP 请求的基础 URL。
///
/// [onCheckNetworkAvailable] 由 [networkMonitorProvider]（公共服务）注入，
/// 请求前先判断网络状态，无网络时直接抛 [ApiError.noNetworkConnection]。
final apiConfigProvider = Provider<ApiConfig>((ref) {
  final networkMonitor = ref.read(networkMonitorProvider);
  final tokenStream = ref.read(_tokenUpdateStreamProvider);

  return ApiConfig(
    baseURL: AppConfig.apiBaseUrl,
    platformHeaders: {
      'platform': DeviceInfo.platform,
      'os-type': DeviceInfo.osType.toString(),
      'client-version': AppConfig.appVersion,
      'channel': AppConfig.channel,
      'lang': DeviceInfo.lang,
      'device-id': DeviceInfo.deviceId,
      'device-name': DeviceInfo.deviceName,
    },
    onTokenRefresh: () async {
      // TODO: App 层刷新 token 逻辑
      return null;
    },
    onTokenUpdated: (newToken) {
      // 通过事件流同步到 WebSocket，避免直接引用 socketManagerProvider 造成循环依赖
      tokenStream.add(newToken);
    },
    onCheckNetworkAvailable: _checkNetwork(networkMonitor),
    // TODO: 接入 cipher_guard_sdk 后注入请求加密回调。
    // 前提：AuthNotifier.login() 中已完成 cipherSdk.setActiveKeyPair(pub, priv)。
    // 示例：
    //   onEncryptRequest: (path, headers, body) async {
    //     final encryptedKey = await cipherSdk.encryptSessionKeyWithActiveKey(
    //       sessionKey: currentSessionKey,
    //     );
    //     return EncryptedRequest(body: encryptedBody, headers: {'X-Key': encryptedKey});
    //   },
    onEncryptRequest: null,
    // TODO: 接入 cipher_guard_sdk 后注入响应解密回调。
    // 前提：与 onEncryptRequest 配套，服务端响应同样加密时启用。
    // 示例：
    //   onDecryptResponse: (data) async {
    //     final plaintext = await cipherSdk.decryptMessage(encryptedData: data as String, ...);
    //     return jsonDecode(plaintext) as Map<String, dynamic>;
    //   },
    onDecryptResponse: null,
    onBusinessError: (code, message, path) {
      switch (code) {
        // Token 过期：SDK 自动刷 token + 重试，业务层无感
        case ApiErrorCodes.tokenInvalid:
        case ApiErrorCodes.jwtInvalid:
        case ApiErrorCodes.sessionInvalid:
          return BusinessErrorAction.refreshToken;

        // Token 刷新失败 / refresh token 失效：强制登出
        case ApiErrorCodes.refreshTokenFailed:
          // TODO: 清除登录态，跳转登录页
          return BusinessErrorAction.forceLogout;

        // 踢下线：账号在其他设备登录、签名/密钥异常
        case ApiErrorCodes.loggedInAnotherDevice:
        case ApiErrorCodes.signingMethodError:
        case ApiErrorCodes.parsingKeyError:
          // TODO: 接入全局 Toast/弹窗机制后展示踢下线提示，并跳转登录页
          return BusinessErrorAction.handled;

        // 触发图片验证：需展示 CAPTCHA 后重发 OTP
        // data 中含 android / ios / web 平台 token（见 SendOtpCaptchaData）
        case ApiErrorCodes.captchaRequired:
          // TODO: 接入 CAPTCHA SDK，验证通过后重发 OTP
          return BusinessErrorAction.handled;

        default:
          // 单接口自行处理（ViewModel 的 guard 会收到 ApiError）
          return BusinessErrorAction.unhandled;
      }
    },
    onTransformResponse:
        null, // TODO: 如后端响应格式非标准，在此归一化为 { code, data, message }
    onGetTokenExpiry: parseJwtExpiry,
    maxRetries: AppConstants.maxRetries,
    retryBaseDelay: AppConstants.retryBaseDelay,
    onLog: _makeLogger('Network'),
  );
});

/// API 客户端 Provider（全局单例）
///
/// 含拦截器（Auth / Retry / Logging）、超时配置。
final networkSdkApiProvider = Provider<NetworksSdkApi>((ref) {
  final config = ref.read(apiConfigProvider);
  return NetworksSdkApi()..initialize(config);
});

// ── WebSocket 基础设施 ────────────────────────────────────────────────────────

/// SocketConfig Provider（内部使用，不对外暴露）
///
/// 与 apiConfigProvider 对称，通过回调注入 App 层能力，
/// SDK 内部不调用其他 SDK。
final _socketConfigProvider = Provider<SocketConfig>((ref) {
  final networkMonitor = ref.read(networkMonitorProvider);
  final apiConfig = ref.read(apiConfigProvider);

  return SocketConfig(
    maxReconnectAttempts: AppConstants.maxRetries,
    maxReconnectDelay: AppConstants.maxReconnectDelay,
    unlimitedReconnect: true, // IM 场景始终保持连接
    // 接入 cipher_guard_sdk 后改为 cipher=true&type=mode3
    onBuildConnectUrl: (url, token) {
      final uri = Uri.parse(url);
      final params = <String, String>{
        ...uri.queryParameters,
        if (token != null) 'token': token, // ignore: use_null_aware_elements
        'cipher': 'true',
        'type': 'mode2',
      };
      return uri.replace(queryParameters: params).toString();
    },
    onEncryptMessage: null, // TODO: 接入 cipher_guard_sdk 后注入消息加密回调
    onDecryptMessage: null, // TODO: 接入 cipher_guard_sdk 后注入消息解密回调
    // SocketClient 内部重连（心跳超时 / stream onDone）前调用
    onBeforeReconnect: () =>
        _proactiveTokenRefresh(apiConfig, logTag: 'Socket'),
    onLog: _makeLogger('Socket'),
    onCheckNetworkAvailable: _checkNetwork(networkMonitor),
  );
});

/// SocketClient Provider（内部使用，不对外暴露）
///
/// 与 networkSdkApiProvider 对称。
final _socketClientProvider = Provider<NetworksMessagingApi>((ref) {
  final config = ref.read(_socketConfigProvider);
  return NetworksMessagingApi()..initialize(config);
});

/// SocketManager Provider
///
/// 封装连接生命周期、网络/前后台事件响应、操作前置检查、消息预处理。
/// 业务模块通过此 Provider 访问 WebSocket 能力。
///
/// ## 前置检查
///
/// connect / send 前先检查网络可用性 + 后台状态，
/// 无效操作直接跳过，避免无意义的网络请求。
/// 与 HTTP 层 [ApiClient.executeRequest] 的网络前置检查对称。
///
/// ## 事件驱动
///
/// 网络状态变化由 [networkMonitorProvider]（公共服务）驱动，
/// 自动触发断连/重连。
///
/// Token 更新由 [_tokenUpdateStreamProvider] 事件流驱动，
/// HTTP 层刷新 token 后自动同步到 WebSocket。
///
/// onMessageTransform 参考 HTTP 层 onTokenRefresh 的回调模式：
/// 后续接入加解密 SDK 时，在此注入解密回调，
/// SDK 内部不调用其他 SDK。
final socketManagerProvider = Provider<SocketManager>((ref) {
  final client = ref.read(_socketClientProvider);
  final networkMonitor = ref.read(networkMonitorProvider);
  final apiConfig = ref.read(apiConfigProvider);
  final tokenStream = ref.read(_tokenUpdateStreamProvider);

  final manager = SocketManager(
    client: client,
    wsUrl: _buildWsUrl(AppConfig.apiBaseUrl),
    disconnectInBackground: false, // 所有平台后台保活，心跳不停、连接不断
    onMessageTransform: null, // TODO: 接入加解密 SDK 后注入解密回调
    // SocketManager 层重连（前台恢复 / 网络恢复）前调用
    onBeforeReconnect: () =>
        _proactiveTokenRefresh(apiConfig, logTag: 'SocketManager'),
    onCheckNetworkAvailable: _checkNetwork(networkMonitor),
    onLog: _makeLogger('SocketManager'),
  );

  // 监听 token 更新事件 → 同步到 WebSocket
  final tokenSub = tokenStream.stream.listen((newToken) {
    manager.updateToken(newToken);
  });

  // 监听网络状态变化 → 驱动 SocketManager 断连/重连
  final networkSub = networkMonitor.onStatusChanged.listen((isAvailable) {
    manager.handleNetworkStatusChanged(isAvailable: isAvailable);
  });

  ref.onDispose(() {
    tokenSub.cancel();
    networkSub.cancel();
    unawaited(manager.dispose());
  });

  return manager;
});

// ── 辅助 ──────────────────────────────────────────────────────────────────────

/// 日志回调工厂，各模块传自己的默认 tag
///
/// SDK 内部调用 onLog 时通常已传 tag，defaultTag 仅作兜底。
OnLog _makeLogger(String defaultTag) => (message, {tag}) {
  debugPrint('[${tag ?? defaultTag}] $message');
};

/// 网络可用性检查回调，HTTP 和 WebSocket 共用
OnCheckNetworkAvailable _checkNetwork(NetworkMonitor monitor) =>
    () async => monitor.isConnected;

/// 重连前主动刷新 token：距过期不足阈值时提前刷新
///
/// 两处调用：
/// - SocketClient 内部重连（心跳超时 / stream onDone）前
/// - SocketManager 重连（前台恢复 / 网络恢复）前
///
/// 刷新后通过 onTokenUpdated → sync stream → socketClient._currentToken 同步更新，
/// 确保随后的 _doConnect() 使用新 token。
Future<void> _proactiveTokenRefresh(
  ApiConfig config, {
  required String logTag,
}) async {
  final currentToken = config.token;
  if (currentToken == null || config.onGetTokenExpiry == null) return;

  final expiry = config.onGetTokenExpiry!(currentToken);
  if (expiry == null) return;

  final remaining = expiry.difference(DateTime.now());
  if (remaining > config.proactiveRefreshThreshold) return;

  debugPrint(
    '[$logTag] Token expiring in ${remaining.inMinutes}min, refreshing before reconnect',
  );
  final newToken = await config.onTokenRefresh?.call();
  if (newToken != null && newToken.isNotEmpty) {
    config.updateToken(newToken);
  }
}

/// HTTP baseURL → WebSocket URL 转换
///
/// https://api.example.com → wss://api.example.com/ws
/// http://api.example.com  → ws://api.example.com/ws
String _buildWsUrl(String httpBaseUrl) {
  String base = httpBaseUrl;
  if (base.startsWith('https://')) {
    base = base.replaceFirst('https://', 'wss://');
  } else if (base.startsWith('http://')) {
    base = base.replaceFirst('http://', 'ws://');
  }
  return '$base${ApiPaths.wsConnect}';
}

// ══════════════════════════════════════════════════════════════════════════════
//  本文件的职责
// ══════════════════════════════════════════════════════════════════════════════
//
//  提供所有网络基础设施 Provider：网络监听 + HTTP + WebSocket。
//  业务模块的 DI 链路（Repository → UseCase 按需）
//  内聚在 features/{模块}/di/{模块}_providers.dart 中。
//
//  di/ 目录只放「需要手动装配的 Provider」（构造注入、回调组合等）。
//  ViewModel Provider 由 @riverpod 注解自动生成，不在 di/ 中。
//
//  ┌──────────────────────────────────────────────────────────────────────────┐
//  │                         DI 架构                                         │
//  ├──────────────────────────────────────────────────────────────────────────┤
//  │  app/di/                         ← 手动装配：SDK 基础设施               │
//  │  ├── app_providers.dart     → 主题 + 启动初始化                         │
//  │  └── network_provider.dart  → 网络监听 + HTTP + WebSocket              │
//  │                                                                         │
//  │  features/{模块}/di/             ← 手动装配：业务模块 DI 链路           │
//  │  └── auth_providers.dart    → Repository → UseCase（按需）              │
//  │      chat_providers.dart       每个模块 DI 链路内聚在一个文件           │
//  │                                                                         │
//  │  features/{模块}/presentation/   ← @riverpod 自动生成：ViewModel        │
//  │  └── login_view_model.dart  → loginViewModelProvider（代码生成）        │
//  └──────────────────────────────────────────────────────────────────────────┘
//
//  Provider 链路：
//
//    networkMonitorProvider（公共服务，HTTP + WS 共用）
//      ├── apiConfigProvider → networkSdkApiProvider      ← HTTP 层
//      └── _socketConfigProvider → _socketClientProvider   ← WS 层（内部）
//            → socketManagerProvider
//
//    _tokenUpdateStreamProvider（打破循环引用的中间层）
//      ← apiConfigProvider.onTokenUpdated 推送
//      → socketManagerProvider 监听 → socketManager.updateToken()
//
//  网络事件驱动链路：
//
//    connectivity_plus（平台网络事件）
//      → NetworkMonitor.onStatusChanged（true / false）
//        → SocketManager.handleNetworkStatusChanged()
//          → 断网: disconnect()
//          → 恢复: onBeforeReconnect → connect(token: lastToken)
//
//  前后台事件驱动链路：
//
//    WidgetsBindingObserver（App 层 app.dart）
//      → SocketManager.onEnterBackground()
//          disconnectInBackground=false → 完全保活，心跳不停（本项目默认）
//          disconnectInBackground=true  → disconnect + 暂停心跳（省电模式）
//      → SocketManager.onEnterForeground()
//          保活模式 → 检查连接健康，异常则重连
//          断连模式 → onBeforeReconnect → reconnect
//
//  Token 刷新 → WebSocket 同步链路：
//
//    RetryInterceptor 检测 token 过期
//      → TokenRefreshManager.refreshIfNeeded()
//      → apiConfig.updateToken(newToken)
//      → onTokenUpdated(newToken)
//      → _tokenUpdateStream.add(newToken)
//      → socketManager.updateToken(newToken)  // 不断连，下次重连自动用新 token
//
//  主动 token 刷新（重连前，两个层级）：
//
//    SocketManager 层（前台恢复 / 网络恢复触发）：
//      SocketManager.onBeforeReconnect()
//        → 解析 JWT exp → 距过期 < 阈值
//        → apiConfig.onTokenRefresh() → 刷新
//        → apiConfig.updateToken(newToken)
//        → sync stream → manager.updateToken → _lastToken 更新
//        → _client.connect(token: _lastToken) 使用新 token
//
//    SocketClient 层（心跳超时 / stream onDone 触发）：
//      SocketConfig.onBeforeReconnect()
//        → 同上逻辑：检查 JWT exp → 刷新 → apiConfig.updateToken
//        → sync stream → manager.updateToken → _client.updateToken
//        → socketClient._currentToken 同步更新
//        → _doConnect() 使用新 token
//
//  Repository 直接注入 ApiClient，通过回调注入其他 SDK 能力：
//
//    onTokenUpdate: (token) {
//      apiConfig.updateToken(token);       // 内存（network_sdk）
//      secureStorage.saveToken(token);     // 持久化（crypto_sdk）
//    }
//
//  这样 network_sdk 和 crypto_sdk 互不依赖，App 层是唯一知道两者的地方。
//
// ══════════════════════════════════════════════════════════════════════════════
//  新增接口的完整流程（以登录为例）
// ══════════════════════════════════════════════════════════════════════════════
//
//  「一个接口 = 一个 Request 文件」，严格按层调用，禁止跳层。
//
//  ┌──────────────────────────────────────────────────────────────────────────┐
//  │                         文件 & 职责总览                                    │
//  ├──────────────────────────────────────────────────────────────────────────┤
//  │  login_request.dart        Request + Response DTO（一个端点一个文件）       │
//  │  auth_repository_impl.dart executeRequest → DTO → Entity + 回调写 Token│
//  │  login_usecase.dart        格式校验 → 调 Repository（按需，非必须）      │
//  │  auth_providers.dart       DI 装配（Repository → UseCase 按需）          │
//  │  login_view_model.dart     ref.read(authRepositoryProvider).login()     │
//  │                            或 ref.read(loginUseCaseProvider).execute()  │
//  │  login_page.dart           ref.watch(loginViewModelProvider)            │
//  └──────────────────────────────────────────────────────────────────────────┘
//
// ─────────────────────────────────────────────────────────────────────────
// Step 1: 定义 Request（data/remote/login_request.dart）
// ─────────────────────────────────────────────────────────────────────────
//
//   一个文件包含两部分：Response DTO + Request 类。
//
//   @JsonSerializable()
//   class LoginData {                               // Response DTO
//     final String token;
//     final String userId;
//     factory LoginData.fromJson(Map<String, dynamic> json) => _$LoginDataFromJson(json);
//     User toEntity() => User(id: userId, ...);     // DTO → Domain Entity
//   }
//
//   @ApiRequest(path: ApiPaths.authLogin, method: HttpMethod.post,
//       responseType: LoginData, requestType: ApiRequestType.login)
//   @JsonSerializable()
//   class LoginRequest extends ApiRequestable<LoginData> with _$LoginRequestApi {
//     final String email;
//     final String password;
//     LoginRequest({required this.email, required this.password});
//     @override Map<String, dynamic> toJson() => _$LoginRequestToJson(this);
//   }
//
//   build_runner 生成 _$LoginRequestApi mixin → 自动提供 path / method / fromJson 注册。
//
// ─────────────────────────────────────────────────────────────────────────
// Step 2: Repository（data/repositories/auth_repository_impl.dart）
// ─────────────────────────────────────────────────────────────────────────
//
//   class AuthRepositoryImpl implements AuthRepository {
//     final ApiClient _client;                        // ← 直接注入 ApiClient
//     final void Function(String?) _onTokenUpdate;    // ← 回调，由 Provider 层组合
//
//     Future<User> login({required String email, required String password}) async {
//       final dto = await _client.executeRequest(
//         LoginRequest(email: email, password: password),
//       );
//       _onTokenUpdate(dto!.token);                   // 回调写入 Token
//       return dto.toEntity();                        // DTO → Domain Entity
//     }
//   }
//
// ─────────────────────────────────────────────────────────────────────────
// Step 3: Provider 装配 + ViewModel
// ─────────────────────────────────────────────────────────────────────────
//
//   // --- Provider 装配（features/auth/di/auth_providers.dart） ---
//
//   // Repository（直接注入 ApiClient + 回调组合多个 SDK 能力）
//   final authRepositoryProvider = Provider((ref) {
//     final apiConfig = ref.read(apiConfigProvider);
//     return AuthRepositoryImpl(
//       client: ref.read(networkSdkApiProvider),    // 注入 Facade 接口
//       onTokenUpdate: (token) {
//         apiConfig.updateToken(token);             // 内存（network_sdk）
//         // secureStorage.saveToken(token);        // 持久化（crypto_sdk）
//       },
//     );
//   });
//
//   // UseCase（按需 — 登录有多步编排，所以需要）
//   final loginUseCaseProvider = Provider((ref) {
//     return LoginUseCase(authRepository: ref.read(authRepositoryProvider));
//   });
//
//   // --- ViewModel（features/auth/presentation/login_view_model.dart） ---
//
//   // 常规写法：ViewModel 直接调 Repository
//   @riverpod
//   class LoginViewModel extends _$LoginViewModel {
//     Future<void> login(String email, String password) async {
//       state = state.copyWith(isLoading: true);
//       try {
//         final user = await ref.read(authRepositoryProvider).login(
//           email: email, password: password,
//         );
//         state = state.copyWith(user: user, isLoading: false);
//       } on ApiError catch (e) {
//         state = state.copyWith(error: e.displayMessage, isLoading: false);
//       }
//     }
//   }
//
//   // 进阶写法：有 UseCase 时（格式校验 + 多步编排）
//   // final user = await ref.read(loginUseCaseProvider).execute(
//   //   email: email, password: password,
//   // );
//
// ═════════════════════════════════════════════════════════════════════════
//  内部执行链路（点击登录按钮后发生了什么）
// ═════════════════════════════════════════════════════════════════════════
//
//   View: vm.login(email, password)
//     → ViewModel: ref.read(authRepositoryProvider).login(...)    ← 常规路径
//     → ViewModel: ref.read(loginUseCaseProvider).execute(...)    ← 进阶路径（有 UseCase 时）
//       → UseCase: 格式校验（邮箱 + 密码）
//       → UseCase/ViewModel: authRepository.login(...)
//         → Repository: _client.executeRequest(LoginRequest(...))
//           → ApiClient.executeRequest(request)
//               1. 拼 URL: baseURL + "/auth/login"
//               2. request.parameters 触发 fromJson 自动注册
//               3. AuthInterceptor: 注入 token + platform headers
//               4. Dio.request(url, data: {email, password})
//               5. RetryInterceptor: token 过期 → 刷新 → 自动重试
//               6. LoggingInterceptor: 打印请求/响应日志
//             → request.decodeResponse(response)
//               1. ApiResponseWrapper.fromJson: 拆 { code, message, data }
//               2. 检查 code != 0 → 抛 ApiError
//               3. fromJsonRegistry[LoginData] → LoginData.fromJson(data)
//             → 返回 LoginData（DTO）
//         → _onTokenUpdate(token)  回调写入 Token（Provider 层组合：内存 + 持久化）
//         → LoginData.toEntity() → User（Domain Entity）
//     → state.copyWith(user: user)  更新状态
//   View: ref.watch → 自动 rebuild UI
//
// ═════════════════════════════════════════════════════════════════════════
//  各 HTTP 方法速查 — 新增接口时参照
// ═════════════════════════════════════════════════════════════════════════
//
//  GET（参数走 URL query string）
//    @ApiRequest(path: ..., method: HttpMethod.get, responseType: ProfileData)
//    class GetProfileRequest extends ApiRequestable<ProfileData> with _$... { }
//
//  POST（参数走 JSON body）
//    见上方 LoginRequest 示例。
//
//  DELETE / PUT / PATCH（与 POST 相同，只改 method）
//    @ApiRequest(path: ..., method: HttpMethod.delete, responseType: ...)
//
//  POST 无响应数据（如 logout）
//    class LogoutRequest extends ApiRequestable<void> { ... }
//    // → 返回 null
//
//  Upload A: FormData 上传到自有后端
//    @override Object? get uploadData => FormData.fromMap({ 'file': ... });
//
//  Upload B: 二进制上传到 S3 presigned URL
//    @override String get path => presignedURL;    // 完整 URL，不拼 baseURL
//    @override Object? get uploadData => bytes;    // Uint8List
//    @override decodeResponse(response) { ... }    // S3 不走标准响应格式
//
