import 'package:dio/dio.dart';
import 'package:wallpaperx/common/components/easy_loading.dart';
import 'package:wallpaperx/common/network/base_error.dart';
import 'package:wallpaperx/common/utils/log_print.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';

class DioClient {
  static final DioClient _instance = DioClient._internal();

  factory DioClient() => _instance;
  late Dio _dio;

  DioClient._internal() {
    _dio = Dio();
    final baseOptions = BaseOptions(
      baseUrl: '',
      connectTimeout: const Duration(seconds: 15),
      receiveTimeout: const Duration(seconds: 10),
    );
    _dio.options = baseOptions;
    _dio.interceptors.add(PrettyDioLogger(
      requestHeader: true,
      requestBody: true,
      compact: false,
    ));
  }

  /// 下载
  Future<void> download(
    String urlPath,
    dynamic savePath, {
    ProgressCallback? onReceiveProgress,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    data,
    Options? options,
    required Function() success,
    Function(String? err)? fail,
  }) async {
    try {
      await _dio.download(
        urlPath,
        savePath,
        onReceiveProgress: onReceiveProgress,
        queryParameters: queryParameters,
        cancelToken: cancelToken,
        data: data,
        options: Options(receiveTimeout: const Duration(seconds: 0)),
      );
      success();
    } on DioException catch (e) {
      BaseError error = getError(e);
      toast(error.message);
      if (fail != null) fail(error.message);
    } catch (e) {
      LogPrint.e(e.toString());
      toast(e.toString());
      if (fail != null) fail(e.toString());
    }
  }

  BaseError getError(DioException e) {
    if (e.runtimeType == DioException) {
      switch (e.type) {
        case DioExceptionType.connectionTimeout:
          return OtherError(statusCode: -1, statusMessage: 'connection timed out');
        case DioExceptionType.sendTimeout:
          return OtherError(statusCode: -1, statusMessage: 'send timeout');
        case DioExceptionType.receiveTimeout:
          return OtherError(statusCode: -1, statusMessage: 'receive timeout');
        case DioExceptionType.badCertificate:
          return OtherError(statusCode: -1, statusMessage: 'certificate error');
        case DioExceptionType.cancel:
          return OtherError(statusCode: -1, statusMessage: 'request canceled');
        case DioExceptionType.connectionError:
          return OtherError(statusCode: -1, statusMessage: 'connection error');
        case DioExceptionType.unknown:
          return OtherError(statusCode: -1, statusMessage: 'unknown error');
        case DioExceptionType.badResponse:
          final response = e.response;
          if (response!.statusCode == 401) {
            return NeedLogin();
          } else if (response.statusCode == 403) {
            return NeedAuth();
          } else {
            return OtherError(
              statusCode: response.statusCode,
              statusMessage: response.statusMessage,
            );
          }
      }
    }
    return OtherError(statusCode: -1, statusMessage: 'unknown error');
  }
}

enum RequestMethod {
  get('GET'),
  post('POST'),
  put('PUT'),
  head('HEAD'),
  delete('DELETE'),
  patch('PATCH');

  const RequestMethod(
    this.method,
  );

  final String method;
}
