import 'dart:io';
import 'package:dio/dio.dart';
import 'package:road24_mobile/data/repository/DevicesRepository.dart';
import 'package:road24_mobile/data/repository/UserRepository.dart';
import 'package:road24_mobile/data/response/AuthResponse.dart';
import 'package:road24_mobile/model/utils/Config.dart';
import 'package:road24_mobile/my_app.dart';
import 'ApiResponse.dart';
import 'CustomDioInterceptor.dart';

String _getLanguage(String language) {
  if (language == 'uz') return 'oz';
  if (language == 'oz') return 'uz';
  return language;
}

BaseOptions dioOptions({String version = 'v1'}) {
  final baseDioOptions = new BaseOptions(
    baseUrl: Config.baseApiUrl.replaceAll('/v1/', '/$version/'),
    headers: {
      'Api-Version': '1.0',
      'Accept': 'application/json',
      'App-OS': Platform.operatingSystem,
      'Accept-Language': _getLanguage(Config.language),
    },
    connectTimeout: 60000,
    receiveTimeout: 60000,
    sendTimeout: 60000,
    contentType: 'application/json',
    responseType: ResponseType.json,
  );
  return baseDioOptions;
}

Dio createDioInstanceForGeneralRequests({String version = 'v1'}) {
  final baseDioOptions = new BaseOptions(
    baseUrl: Config.baseApiUrl.replaceAll('/v1/', '/$version/'),
    headers: {
      'Api-Version': '1.0',
      'Accept': 'application/json',
      'App-OS': Platform.operatingSystem,
      'Accept-Language': _getLanguage(Config.language),
    },
    connectTimeout: 60000,
    receiveTimeout: 60000,
    sendTimeout: 60000,
    contentType: 'application/json',
    responseType: ResponseType.json,
  );

  final dio = Dio(baseDioOptions);

  dio.interceptors.add(CustomDioInterceptor(
    responseBody: true,
    requestBody: true,
    requestHeader: true,
  ));
  return dio;
}

Dio createDioToUploadFile({String version = 'v1'}) {
  final baseDioOptions = new BaseOptions(
    baseUrl: Config.baseFilesApiUrl.replaceAll('/v1/', '/$version/'),
    headers: {
      'Api-Version': '1.0',
      'Accept': 'application/json',
      'App-OS': Platform.operatingSystem,
      'Accept-Language': _getLanguage(Config.language),
    },
    connectTimeout: 60000,
    receiveTimeout: 60000,
    sendTimeout: 60000,
    contentType: 'application/json',
    responseType: ResponseType.json,
  );
  final dio = Dio(baseDioOptions);
  dio.interceptors.add(CustomDioInterceptor(
    responseBody: true,
    requestBody: true,
    requestHeader: true,
  ));
  return dio;
}

Future<ApiResponse?> doGetRequest(
  String url, {
  Map<String, dynamic>? queryParameters,
  String version = 'v1',
}) async {
  try {
    final response = await createDioInstanceForGeneralRequests(version: version)
        .get(url, queryParameters: queryParameters);

    return success(response);
  } catch (error) {
    if (error is DioError) {
      print("message:  " + error.message);
      print("error:  " + error.error.toString());
      print("response:  " + error.response.toString());
      if (error.response?.statusCode == 403 ||
          error.response?.statusCode == 401) {
        print("path:   " + error.requestOptions.uri.path);
        // if (error.requestOptions.uri.path ==
        //     '/api/mobile/v1/users/auth/token/refresh/') {
        //   MyApp.navigatorKey.currentState!.pushAndRemoveUntil(
        //       FadeRoute(page: PhonePage()), (route) => false);

        //   setTokens(null, null);
        //   return null;
        // }

        await refreshToken();

        return await createDioInstanceForGeneralRequests(version: version)
            .get(
          url,
          queryParameters: queryParameters,
        )
            .then((value) {
          ApiResponse apiResponse = ApiResponse.fromJson(value.data);
          return apiResponse;
        });
      } else {
        print("UNDEFINED ERROR");
        if (error.toString().contains("SocketException") ||
            error.toString().contains("TimeOutException")) {
          print("socket error 1 ");
          MyApp.hasInternet.value = false;

          throw Exception(error.response!.statusCode.toString());
        }
        throw Exception(
            error.toString() + error.response!.statusCode.toString());
      }
    }
  }
}

Future<ApiResponse?> doPostRequest(
  String url, {
  dynamic data,
  Map<String, dynamic>? queryParameters,
  bool ignoreApiError: false,
  Options? options,
  String version = 'v1',
}) async {
  print("url $url");
  try {
    final response =
        await createDioInstanceForGeneralRequests(version: version).post(
      url,
      data: data,
      queryParameters: queryParameters,
      options: options,
    );

    return success(response, ignoreApiError: ignoreApiError);
  } catch (error) {
    print("post error....$error");
    if (error is DioError) {
      print("Headers...${error.response?.headers.toString()}");

      if (error.response?.statusCode == 403 ||
          error.response?.statusCode == 401) {
        print("error post.....:" + error.requestOptions.uri.path);
        // if (error.requestOptions.uri.path ==
        //     '/api/mobile/v1/users/auth/token/refresh/') {
        //   MyApp.navigatorKey.currentState!.pushAndRemoveUntil(
        //       FadeRoute(page: PhonePage()), (route) => false);
        //   setTokens(null, null);
        //   return null;
        // }

        await refreshToken();

        return await createDioInstanceForGeneralRequests(version: version)
            .post(
          url,
          data: data,
          queryParameters: queryParameters,
          options: options,
        )
            .then((value) {
          ApiResponse apiResponse = ApiResponse.fromJson(value.data);
          return apiResponse;
        });
      } else {
        if (error.toString().contains("SocketException") ||
            error.toString().contains("TimeOutException")) {
          print("socket error 1 ");
          MyApp.hasInternet.value = false;

          throw Exception(error.response!.statusCode.toString());
        }
        throw Exception(error.response!.data.toString() +
            error.response!.statusCode.toString());
      }
    }
  }
}

Future<ApiResponse?> doPutRequest(
  String url, {
  dynamic data,
  Map<String, dynamic>? queryParameters,
  bool ignoreApiError: false,
  Options? options,
  String version = 'v1',
}) async {
  try {
    final response =
        await createDioInstanceForGeneralRequests(version: version).put(
      url,
      data: data,
      queryParameters: queryParameters,
      options: options,
    );

    return success(response, ignoreApiError: ignoreApiError);
  } catch (error) {
    print("B");
    if (error is DioError) {
      if (error.response?.statusCode == 403 ||
          error.response?.statusCode == 401) {
        print("C");
        print(error.requestOptions.uri.path);
        // if (error.requestOptions.uri.path ==
        //     '/api/mobile/v1/users/auth/token/refresh/') {
        //   print("D");
        //   MyApp.navigatorKey.currentState!.pushAndRemoveUntil(
        //       FadeRoute(page: PhonePage()), (route) => false);
        //   setTokens(null, null);
        //   return null;
        // }

        await refreshToken();

        return await createDioInstanceForGeneralRequests(version: version)
            .put(
          url,
          data: data,
          queryParameters: queryParameters,
          options: options,
        )
            .then((value) {
          ApiResponse apiResponse = ApiResponse.fromJson(value.data);
          return apiResponse;
        });
      } else {
        if (error.toString().contains("SocketException") ||
            error.toString().contains("TimeOutException")) {
          print("socket error 1 ");
          MyApp.hasInternet.value = false;

          throw Exception(error.response!.statusCode.toString());
        }
        throw Exception(error.response!.data.toString() +
            error.response!.statusCode.toString());
      }
    }
  }
}

Future<ApiResponse?> doPatchRequest(
  String url, {
  dynamic data,
  Map<String, dynamic>? queryParameters,
  bool ignoreApiError: false,
  Options? options,
  String version = 'v1',
}) async {
  try {
    final response =
        await createDioInstanceForGeneralRequests(version: version).patch(
      url,
      data: data,
      queryParameters: queryParameters,
      options: options,
    );
    return success(response, ignoreApiError: ignoreApiError);
  } catch (error) {
    if (error is DioError) {
      if (error.response?.statusCode == 403 ||
          error.response?.statusCode == 401) {
        print("PATH");
        print(error.requestOptions.uri.path);
        // if (error.requestOptions.uri.path ==
        //     '/api/mobile/v1/users/auth/token/refresh/') {
        //   MyApp.navigatorKey.currentState!.pushAndRemoveUntil(
        //       FadeRoute(page: PhonePage()), (route) => false);
        //   setTokens(null, null);
        //   return null;
        // }

        await refreshToken();

        return await createDioInstanceForGeneralRequests(version: version)
            .patch(
          url,
          data: data,
          queryParameters: queryParameters,
          options: options,
        )
            .then((value) {
          ApiResponse apiResponse = ApiResponse.fromJson(value.data);
          return apiResponse;
        });
      } else {
        if (error.toString().contains("SocketException") ||
            error.toString().contains("TimeOutException")) {
          print("socket error 1 ");
          MyApp.hasInternet.value = false;

          throw Exception(error.response!.statusCode.toString());
        }
        throw Exception(error.response!.data.toString() +
            error.response!.statusCode.toString());
      }
    }
  }
}

Future<ApiResponse?> doDeleteRequest(
  String url, {
  Map<String, dynamic>? queryParameters,
  String version = 'v1',
}) async {
  try {
    final response = await createDioInstanceForGeneralRequests(version: version)
        .delete(url, queryParameters: queryParameters);
    if (response.statusCode == 204) {
      ApiResponse apiResponse = ApiResponse.fromJson(response.data);
      if (apiResponse.isSuccess()) return apiResponse;
    }
  } catch (error) {
    if (error is DioError) {
      if (error.response?.statusCode == 403 ||
          error.response?.statusCode == 401) {
        // if (error.requestOptions.uri.path ==
        //     '/api/mobile/v1/users/auth/token/refresh/') {
        //   MyApp.navigatorKey.currentState!.pushAndRemoveUntil(
        //       FadeRoute(page: PhonePage()), (route) => false);
        //   setTokens(null, null);
        //   return null;
        // }
        await refreshToken();

        return await createDioInstanceForGeneralRequests(version: version)
            .delete(
          url,
          queryParameters: queryParameters,
        )
            .then((value) {
          ApiResponse apiResponse = ApiResponse.fromJson(value.data);
          return apiResponse;
        });
      } else {
        if (error.toString().contains("SocketException") ||
            error.toString().contains("TimeOutException")) {
          print("socket error 1 ");
          MyApp.hasInternet.value = false;

          throw Exception(error.response!.statusCode.toString());
        }
        throw Exception(error.response!.data.toString() +
            error.response!.statusCode.toString());
      }
    }
  }
}

refreshToken() async {
  var value = await UserRepository()
      .tokenRefresh(refresh: MyApp.preferences?.getRefreshToken() ?? '');
  print("refreshToken....${MyApp.preferences?.getRefreshToken()}");
  try {
    setTokens(AuthResponse.fromJson(value).access,
        AuthResponse.fromJson(value).refresh);
  } catch (e) {
    if (e is DioError) {
      MyApp.hasInternet.value = false;

      throw Exception(e.response!.statusCode.toString());
    }
  }
}

Future<ApiResponse?> doGetWithPublicUrlRequest(
  String url, {
  Map<String, dynamic>? queryParameters,
  String version = 'v1',
}) async {
  try {
    final response = await createDioInstanceForUpload()
        .get(url, queryParameters: queryParameters);
    return success(response);
  } catch (error) {
    print("error in ApiRequest....:" + error.toString());
    if (error is DioError) {
      print("message:  " + error.message);
      print("error:  " + error.error.toString());
      print("response:  " + error.response.toString());
      if (error.response?.statusCode == 403 ||
          error.response?.statusCode == 401) {
        // if (error.requestOptions.uri.path ==
        //     '/api/mobile/v1/users/auth/token/refresh/') {
        //   MyApp.navigatorKey.currentState!.pushAndRemoveUntil(
        //       FadeRoute(page: PhonePage()), (route) => false);

        //   setTokens(null, null);

        //   return null;
        // }

        await refreshToken();

        return await createDioInstanceForUpload()
            .get(
          url,
          queryParameters: queryParameters,
        )
            .then((value) {
          ApiResponse apiResponse = ApiResponse.fromJson(value.data);
          return apiResponse;
        });
      } else {
        print("UNDEFINED ERROR get");
        if (error.toString().contains("SocketException") ||
            error.toString().contains("TimeOutException")) {
          print("socket error 1 ");
          MyApp.hasInternet.value = false;

          throw Exception(error.response!.statusCode.toString());
        }

        throw Exception(error.response!.data.toString() +
            error.response!.statusCode.toString());
      }
    } else if (error.toString().contains("SocketException")) {
      print("socket error 2");
      MyApp.hasInternet.value = false;
    }
  }
}

Dio createDioInstanceForUpload() {
  Dio dio = Dio(BaseOptions(
    baseUrl: Config.baseApiPublicUrl,
    headers: {
      'Api-Version': '1.0',
      'Accept': 'application/json',
      'App-OS': Platform.operatingSystem,
      'Accept-Language': _getLanguage(Config.language),
    },
    connectTimeout: 60000,
    receiveTimeout: 60000,
    sendTimeout: 60000,
    contentType: 'application/json',
    responseType: ResponseType.json,
  ));
  dio.interceptors.add(CustomDioInterceptor(
    responseBody: true,
    requestBody: true,
    requestHeader: true,
  ));

  return dio;
}

final Dio dio1 = createDioInstanceForUpload();

Future<dynamic> doUploadRequest(
  String url, {
  dynamic data,
  Map<String, dynamic>? queryParameters,
  bool ignoreApiError: false,
  Options? options,
  Function? onSendProgress,
}) async {
  Dio dio = createDioInstanceForUpload();
  try {
    final response = await dio.post(url,
        data: data,
        queryParameters: queryParameters,
        options: options,
        onSendProgress: (count, total) => onSendProgress);
    if (response.statusCode! >= 200 && response.statusCode! < 300) {
      return response.data;
    }
  } catch (error) {
    if (error is DioError) {
      if (error.response?.statusCode == 403 ||
          error.response?.statusCode == 401) {
        await refreshToken();
        return await dio
            .post(url,
                data: data,
                queryParameters: queryParameters,
                options: options,
                onSendProgress: (count, total) => onSendProgress)
            .then((value) {
          if (value.statusCode! >= 200 && value.statusCode! < 300) {
            return value.data;
          }
        });
      } else {
        print("UNDEFINED ERROR get");
        if (error.toString().contains("SocketException") ||
            error.toString().contains("TimeOutException")) {
          print("socket error 1 ");
          MyApp.hasInternet.value = false;

          throw Exception(error.response!.statusCode.toString());
        }

        throw Exception(error.response!.data.toString() +
            error.response!.statusCode.toString());
      }
    }
  }
}

Future<dynamic> uploadImage(String filePath, String fileName) async {
  var dio = createDioToUploadFile();
  var url = "/files/";

  fileName = filePath.split('/').last;

  print("path....$filePath, name...$fileName");
  FormData formData = FormData.fromMap({
    "file": await MultipartFile.fromFile(filePath, filename: fileName),
  });
  try {
    var response = await dio.post(url, data: formData);
    if (response.statusCode! >= 200 && response.statusCode! < 300) {
      return response;
    }
  } catch (error) {
    if (error is DioError) {
      if (error.response?.statusCode == 403 ||
          error.response?.statusCode == 401) {
        await refreshToken();
        var response = await dio.post(
          url,
          data: formData,
        );
        if (response.statusCode! >= 200 && response.statusCode! < 300) {
          return response;
        }
      } else {
        print("UNDEFINED ERROR get");
        if (error.toString().contains("SocketException") ||
            error.toString().contains("TimeOutException")) {
          print("socket error 1 ");
          MyApp.hasInternet.value = false;

          throw Exception(error.response!.statusCode.toString());
        }

        throw Exception(error.response!.data.toString() +
            error.response!.statusCode.toString());
      }
    } else if (error.toString().contains("SocketException")) {
      print("socket error 2");
      MyApp.hasInternet.value = false;
    }
  }
}

success(Response? response, {bool? ignoreApiError}) {
  if (response?.statusCode == 200 ||
      response?.statusCode == 202 ||
      response?.statusCode == 201) {
    ApiResponse apiResponse = ApiResponse.fromJson(response?.data);
    if (ignoreApiError != null) {
      if (ignoreApiError || apiResponse.isSuccess()) return apiResponse;
    } else if (apiResponse.isSuccess()) {
      return apiResponse;
    }
  }
}

errors(String path) async {
  // if (path == '/api/mobile/v1/users/auth/token/refresh/') {
  //   MyApp.navigatorKey.currentState!
  //       .pushAndRemoveUntil(FadeRoute(page: PhonePage()), (route) => false);
  //   setTokens(null, null);
  //   return null;
  // }
  await UserRepository()
      .tokenRefresh(refresh: MyApp.preferences?.getRefreshToken() ?? '')
      .then((value) {
    try {
      setTokens(AuthResponse.fromJson(value).access,
          AuthResponse.fromJson(value).refresh);
    } catch (e) {
      MyApp.hasInternet.value = false;
    }
  });
}

BaseOptions baseDioOptionsForGeoCoding = new BaseOptions(
  baseUrl: "https://maps.googleapis.com/maps/api",
  connectTimeout: 20000,
  receiveTimeout: 20000,
  sendTimeout: 20000,
  contentType: 'application/json',
  responseType: ResponseType.json,
);

Dio createDioInstanceForGeoCoding() {
  Dio dio = new Dio(baseDioOptionsForGeoCoding)..interceptors;

  dio.interceptors.add(CustomDioInterceptor(
    responseBody: true,
    requestBody: true,
    requestHeader: true,
  ));

  return dio;
}

final Dio dio2 = createDioInstanceForGeoCoding();

checkAddressApi(
  String url, {
  Map<String, dynamic>? queryParameters,
}) async {
  try {
    final response = await dio2.get(url, queryParameters: queryParameters);
    if (response.statusCode == 200) {
      return response.data;
    }
  } catch (error) {
    if (error is DioError) {}
  }
}
