/*
 * 网络请求引擎
 */
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:shared/utils/log_utils.dart';
import 'package:shared/utils/reg_utils.dart';
import 'dart:typed_data';
import '../../http/dio/interceptor_cache_controller.dart';
import '../../http/dio/interceptor_network_debounce.dart';
import '../../http/http_provider.dart';

/*
 * 网络请求引擎封装，目前使用的是 Dio 框架
 */
class NetworkEngine {
  late Dio dio;
  late String baseUrl;
  List<Interceptor>? interceptors;

  NetworkEngine(this.baseUrl, this.interceptors) {
    /// 网络配置
    _initializeDio();
  }

  void _initializeDio() {
    final options = BaseOptions(
        baseUrl: baseUrl,
        connectTimeout: const Duration(seconds: 30),
        sendTimeout: const Duration(seconds: 30),
        receiveTimeout: const Duration(seconds: 30),
        validateStatus: (code) {
          //指定这些HttpCode都算成功
          if (code == 200 || code == 401 || code == 422 || code == 429) {
            return true;
          } else {
            return false;
          }
        });

    dio = Dio(options);

    // 设置Dio的转换器
    dio.transformer = BackgroundTransformer(); //Json后台线程处理优化（可选）

    // 设置Dio的拦截器
    dio.interceptors.add(NetworkDebounceInterceptor()); //处理网络请求去重逻辑
    // dio.interceptors.add(AuthDioInterceptors()); //处理请求之前的请求头（项目业务逻辑）
    // dio.interceptors.add(StatusCodeDioInterceptors()); //处理响应之后的状态码（项目业务逻辑）
    dio.interceptors.add(CacheControlInterceptor()); //处理 Http Get 请求缓存策略

    if (!kReleaseMode) {
      dio.interceptors.add(LogInterceptor(responseBody: false)); //默认的 Dio 自带的 Log 打印
    }

    if (interceptors != null) {
      interceptors!.forEach((interceptor) {
        dio.interceptors.add(interceptor);
      });
    }
  }

  //切换BaseUrl
  void switchBaseUrlAndDio(String url) {
    this.baseUrl = url;
    _initializeDio();
  }

  /// 网络请求 Post 请求
  Future<Response> executePost({
    required String url,
    Map<String, dynamic>? params,
    Map<String, String>? paths, //文件
    Map<String, Uint8List>? pathStreams, //文件流
    Map<String, String>? headers,
    ProgressCallback? send, // 上传进度监听
    ProgressCallback? receive, // 下载监听
    CancelToken? cancelToken, // 用于取消的 token，可以多个请求绑定一个 token
  }) async {
    var map = <String, dynamic>{};

    if (params != null || paths != null || pathStreams != null) {
      //只要有一个不为空，就可以封装参数

      //默认的参数
      if (params != null) {
        map.addAll(params);
      }

      //File 文件
      if (paths != null && paths.isNotEmpty) {
        for (final entry in paths.entries) {
          final key = entry.key;
          final value = entry.value;

          if (value.isNotEmpty && RegCheckUtils.isLocalImagePath(value) && _isImageFile(value)) {
            // 以文件的方式压缩，获取到流对象
            Uint8List? stream = await FlutterImageCompress.compressWithFile(
              value,
              minWidth: 1000,
              minHeight: 1000,
              quality: 80,
            );

            //传入压缩之后的流对象
            if (stream != null) {
              map[key] = MultipartFile.fromBytes(stream, filename: "file");
            } else {
              //如果压缩失败使用原始路径File
              map[key] = MultipartFile.fromFileSync(value, filename: "file");
            }
          } else {
            //如果不是图片使用原始路径File
            map[key] = MultipartFile.fromFileSync(value, filename: "file");
          }
        }
      }

      //File 文件流
      if (pathStreams != null && pathStreams.isNotEmpty) {
        for (final entry in pathStreams.entries) {
          final key = entry.key;
          final value = entry.value;

          if (value.isNotEmpty && _isImage(value)) {
            // 以流方式压缩，获取到流对象
            Uint8List stream = await FlutterImageCompress.compressWithList(
              value,
              minWidth: 1000,
              minHeight: 1000,
              quality: 80,
            );

            //传入压缩之后的流对象
            if (stream != null) {
              map[key] = MultipartFile.fromBytes(stream, filename: "file_stream");
            } else {
              //如果压缩失败使用原始流
              map[key] = MultipartFile.fromBytes(value, filename: "file_stream");
            }
          } else {
            //如果不是图片使用原始流
            map[key] = MultipartFile.fromBytes(value, filename: "file_stream");
          }
        }
      }
    }

    final formData = FormData.fromMap(map);

    if (!kReleaseMode) {
      print('单独打印 Post 请求 FromData 参数为：fields:${formData.fields.toString()} files:${formData.files.toString()}');
    }

    return dio.post(
      url,
      data: formData,
      options: Options(headers: headers),
      onSendProgress: send,
      onReceiveProgress: receive,
      cancelToken: cancelToken,
    );
  }

  /// 网络请求 Get 请求
  Future<Response> executeGet({
    required String url,
    Map<String, dynamic>? params,
    Map<String, String>? headers,
    CacheControl? cacheControl,
    Duration? cacheExpiration,
    ProgressCallback? receive, // 请求进度监听
    CancelToken? cancelToken, // 用于取消的 token，可以多个请求绑定一个 token
  }) {
    return dio.get(
      url,
      queryParameters: params,
      options: Options(headers: headers),
      onReceiveProgress: receive,
      cancelToken: cancelToken,
    );
  }

  /// Dio 网络下载
  Future<void> downloadFile({
    required String url,
    required String savePath,
    ProgressCallback? receive, // 下载进度监听
    CancelToken? cancelToken, // 用于取消的 token，可以多个请求绑定一个 token
    void Function(bool success, String path)? callback, // 下载完成回调函数
  }) async {
    try {
      await dio.download(
        url,
        savePath,
        onReceiveProgress: receive,
        cancelToken: cancelToken,
      );
      // 下载成功
      callback?.call(true, savePath);
    } on DioException catch (e) {
      Log.e("DioException：$e");
      // 下载失败
      callback?.call(false, savePath);
    }
  }

  //检查该路径的文件是否是图片类型
  bool _isImageFile(String path) {
    // 定义支持的图片扩展名
    const List<String> imageExtensions = [
      'jpg',
      'jpeg',
      'png',
      'bmp',
      'webp',
    ];

    if (!path.contains('.')) return false;

    // 提取文件扩展名
    final String extension = path.split('.').last.toLowerCase();
    return imageExtensions.contains(extension);
  }

  //校验文件流是否是图片类型
  bool _isImage(Uint8List bytes) {
    if (bytes.length < 8) return false; // 确保有足够数据检测

    // 检测常见图片格式
    return _isJPEG(bytes) || _isPNG(bytes) || _isWebP(bytes) || _isBMP(bytes);
  }

  bool _isJPEG(Uint8List bytes) {
    return bytes.length >= 2 && bytes[0] == 0xFF && bytes[1] == 0xD8;
  }

  bool _isPNG(Uint8List bytes) {
    return bytes.length >= 8 &&
        bytes[0] == 0x89 &&
        bytes[1] == 0x50 && // P
        bytes[2] == 0x4E && // N
        bytes[3] == 0x47 && // G
        bytes[4] == 0x0D && // CR
        bytes[5] == 0x0A && // LF
        bytes[6] == 0x1A && // EOF
        bytes[7] == 0x0A; // LF
  }

  bool _isWebP(Uint8List bytes) {
    return bytes.length >= 12 &&
        bytes[0] == 0x52 && // R
        bytes[1] == 0x49 && // I
        bytes[2] == 0x46 && // F
        bytes[3] == 0x46 && // F
        bytes[8] == 0x57 && // W
        bytes[9] == 0x45 && // E
        bytes[10] == 0x42 && // B
        bytes[11] == 0x50; // P
  }

  bool _isBMP(Uint8List bytes) {
    return bytes.length >= 2 &&
        bytes[0] == 0x42 && // B
        bytes[1] == 0x4D; // M
  }
}
