// api.dart
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:yumi/app/constants/sc_global_config.dart';
import 'package:yumi/ui_kit/components/sc_tts.dart';
import 'package:yumi/shared/tools/sc_room_utils.dart';
import 'package:yumi/shared/data_sources/sources/local/user_manager.dart';
import 'package:yumi/modules/auth/login_route.dart';
import 'package:yumi/app/routes/sc_fluro_navigator.dart';
import 'package:yumi/shared/tools/sc_loading_manager.dart';
import 'package:yumi/main.dart';
import 'package:yumi/shared/data_sources/sources/remote/net/network_client.dart';

import '../../../models/enum/sc_erro_code.dart';

export 'package:dio/dio.dart';

_parseAndDecode(String response) => jsonDecode(response);

parseJson(String text) => compute(_parseAndDecode, text);

String _normalizeAuthorizationHeader(Object? authorization) {
  if (authorization == null) {
    return "";
  }
  if (authorization is Iterable) {
    return authorization.map((value) => value.toString()).join(",");
  }
  return authorization.toString().trim();
}

bool _shouldLogoutForUnauthorized(DioException e) {
  final currentToken = AccountStorage().getToken();
  if (currentToken.isEmpty) {
    return false;
  }
  final requestAuthorization = _normalizeAuthorizationHeader(
    e.requestOptions.headers["Authorization"],
  );
  if (requestAuthorization.isEmpty) {
    return false;
  }
  return requestAuthorization == "Bearer $currentToken";
}

Future<bool> _isCurrentSessionStillValid(DioException e) async {
  if (!_shouldLogoutForUnauthorized(e)) {
    return true;
  }

  final verificationHeaders = Map<String, dynamic>.from(e.requestOptions.headers)
    ..remove("Content-Length")
    ..remove("content-length");

  final verificationClient = Dio(
    BaseOptions(
      baseUrl:
          e.requestOptions.baseUrl.isNotEmpty
              ? e.requestOptions.baseUrl
              : SCGlobalConfig.apiHost,
      connectTimeout: const Duration(seconds: 5),
      receiveTimeout: const Duration(seconds: 5),
      sendTimeout: const Duration(seconds: 5),
      responseType: ResponseType.json,
      validateStatus: (status) => status != null && status < 500,
    ),
  );

  try {
    final verificationResponse = await verificationClient.get(
      "/app/h5/identity",
      options: Options(headers: verificationHeaders),
    );
    final responseData = verificationResponse.data;

    if (verificationResponse.statusCode == 401) {
      return false;
    }

    if (responseData is Map<String, dynamic>) {
      if (responseData["status"] == true) {
        return true;
      }
      if (responseData["errorCode"] == SCErroCode.authUnauthorized.code) {
        return false;
      }
    }
  } on DioException catch (verificationError) {
    final responseData = verificationError.response?.data;
    if (verificationError.response?.statusCode == 401) {
      return false;
    }
    if (responseData is Map<String, dynamic> &&
        responseData["errorCode"] == SCErroCode.authUnauthorized.code) {
      return false;
    }
  } catch (_) {}

  // 校验结果不明确时不要主动登出，避免单条接口抖动把整次登录踢掉。
  return true;
}

class BaseNetworkClient {
  final Dio dio;

  BaseNetworkClient() : dio = Dio() {
    _confD();
    init();
  }

  void _confD() {
    dio.transformer = BackgroundTransformer()..jsonDecodeCallback = parseJson;
    dio.options = BaseOptions(
      connectTimeout: const Duration(seconds: 12),
      receiveTimeout: const Duration(seconds: 30),
      contentType: 'application/json; charset=UTF-8',
    );
  }

  void init() {}

  // 通用 GET 请求
  Future<T> get<T>(
    String path, {
    Map<String, dynamic>? queryParams,
    required T Function(dynamic) fromJson,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    return _req<T>(
      path,
      method: 'GET',
      queryParams: queryParams,
      fromJson: fromJson,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );
  }

  // 通用 put 请求
  Future<T> put<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParams,
    required T Function(dynamic) fromJson,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    return _req<T>(
      path,
      method: 'PUT',
      data: data,
      queryParams: queryParams,
      fromJson: fromJson,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );
  }

  // 通用 POST 请求
  Future<T> post<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParams,
    required T Function(dynamic) fromJson,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    return _req<T>(
      path,
      method: 'POST',
      data: data,
      queryParams: queryParams,
      fromJson: fromJson,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );
  }

  // 通用 POST 请求
  Future<T> delete<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParams,
    required T Function(dynamic) fromJson,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    return _req<T>(
      path,
      method: 'DELETE',
      data: data,
      queryParams: queryParams,
      fromJson: fromJson,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );
  }

  // 核心请求方法
  Future<T> _req<T>(
    String path, {
    required String method,
    dynamic data,
    Map<String, dynamic>? queryParams,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
    required T Function(dynamic) fromJson,
  }) async {
    try {
      final response = await dio.request(
        path,
        data: data,
        queryParameters: queryParams,
        options: Options(method: method),
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress,
      );

      // 处理基础响应
      final baseResponse = ResponseData.fromJson(
        response.data as Map<String, dynamic>,
        fromJsonT: fromJson,
      );
      // 业务逻辑成功判断
      if (baseResponse.success) {
        if (baseResponse.body != null) {
          return baseResponse.body!;
        } else {
          if (T == bool) return false as T;
          if (T == int) return 0 as T;
          if (T == String) return "" as T;
          SCLoadingManager.hide();
          throw Exception('Response data is null');
        }
      } else {
        // 业务逻辑错误
        SCLoadingManager.hide();
        throw DioException(
          requestOptions: response.requestOptions,
          response: response,
          error: '业务错误: ${baseResponse.errorMsg}',
        );
      }
    } on DioException catch (e) {
      // 网络错误处理
      throw await _hdlErr(e);
    } catch (e) {
      SCLoadingManager.hide();
      throw Exception('未知错误: $e');
    }
  }

  // 错误处理
  Future<DioException> _hdlErr(DioException e) async {
    SCLoadingManager.hide();
    switch (e.type) {
      case DioExceptionType.connectionTimeout:
        return DioException(requestOptions: e.requestOptions, error: '连接超时');
      case DioExceptionType.sendTimeout:
        return DioException(requestOptions: e.requestOptions, error: '发送超时');
      case DioExceptionType.receiveTimeout:
        return DioException(requestOptions: e.requestOptions, error: '接收超时');
      case DioExceptionType.badResponse:
        var errorCode = e.response?.data["errorCode"];
        var errorMsg = e.response?.data["errorMsg"];
        if (errorCode == SCErroCode.userNotRegistered.code) {
          //用户还没有注册
          SCTts.show("Please register an account first.");
          BuildContext? context = navigatorKey.currentContext;
          if (context != null) {
            SCNavigatorUtils.push(
              context,
              LoginRouter.editProfile,
              replace: false,
            );
          }
        } else if (errorCode == SCErroCode.authUnauthorized.code) {
          //token过期
          final shouldLogout =
              !SCNavigatorUtils.inLoginPage &&
              !await _isCurrentSessionStillValid(e);
          final BuildContext? context = navigatorKey.currentContext;
          if (context != null && shouldLogout) {
            AccountStorage().logout(context);
            SCNavigatorUtils.inLoginPage = true;
          }
        } else {
          if (errorMsg.toString().endsWith("balance not made")) {
            BuildContext? context = navigatorKey.currentContext;
            if (context != null) {
              SCRoomUtils.goRecharge(context);
            }
          } else {
            SCTts.show(errorMsg);
          }
        }
        return DioException(
          requestOptions: e.requestOptions,
          response: e.response,
          error: '服务器错误: ${e.response?.data["errorCode"]}',
        );
      case DioExceptionType.cancel:
        return DioException(requestOptions: e.requestOptions, error: 'Cancel');
      default:
        return DioException(
          requestOptions: e.requestOptions,
          error: 'Net fail',
        );
    }
  }
}

class NotSuccessException implements Exception {
  final String message;

  NotSuccessException(this.message);

  factory NotSuccessException.fromRespData(ResponseData respData) {
    return NotSuccessException(respData.errorMsg ?? "操作失败");
  }
}
