import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:telnow_mobile_new/src/injector/injector.dart';
import 'package:telnow_mobile_new/src/model/login/login_body.dart';
import 'package:telnow_mobile_new/src/model/refreshtoken/refresh_token_body.dart';
import 'package:telnow_mobile_new/src/model/token/token.dart';
import 'package:telnow_mobile_new/src/layouts/components/template.dart';
import 'package:telnow_mobile_new/src/storage/sharedpreferences/shared_preferences_manager.dart';
import 'package:telnow_mobile_new/src/utils/dio_logging_interceptors.dart';
import 'package:telnow_mobile_new/src/utils/U.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:http/http.dart' as http;

const String host = '';
// const String host = 'bridge3.telmessenger.com';
// const String host = '192.168.100.19:8080';
// const String host = '192.168.100.18:8080';

class ApiAuthProvider {
  final Dio _dio = new Dio();
  final SharedPreferencesManager _sharedPreferencesManager = locator<SharedPreferencesManager>();

  final String displayVersion = '4.0.15'; //versi aplikasi untuk di tampilkan
  final int currentVersion = 40; //versi aplikasi yang digunakan untuk pengecekan versi
  final String buildNumber = '2508.01';

//  final String companyName = '999';
//  final String _baseUrl = 'http://139.162.7.140:9090/';
//  final String _baseUrl = 'http://192.168.100.14:8080/'; //irma
//  final String _baseUrl = 'http://192.168.100.68:8080/'; //mita
//  final String _baseUrl = 'http://192.168.100.121:8080/'; //abi

//  String companyCode = '001';
  late String baseUrl = 'https://$host/';
  // final String baseUrl = 'http://$host/';
  final String clientId = 'inf-G52G4op8N8';
  final String clientSecret = '3JskYu5zxlXRDv6g';
  final String clientIdWeb = 'web-apHca0ncOX';
  final String clientSecretWeb = '1qeIwW8Wu9AF4DRF';
  var isDebug;

  ApiAuthProvider() {
//     print('ApiAuthProvider called');
//     print(U.getAccessCode());
//     isDebug = _sharedPreferencesManager.getBool(SharedPreferencesManager.keyIsDebug);
//     if (_sharedPreferencesManager
//         .isKeyExists(SharedPreferencesManager.keyAccessCode)) {
//       _dio.options.baseUrl = baseUrl + U.decryptAESCryptoJS(U.getAccessCode(), U.passphrase);
// //      _dio.options.baseUrl = baseUrl + U.getAccessCode();
//       _dio.interceptors.add(DioLoggingInterceptors(_dio));
//     }
    init();
  }

  init(){
    // print('ApiAuthProvider called');
    // print("U.getAccessCode() ==> ${U.getAccessCode()}");
    isDebug = _sharedPreferencesManager.getBool(SharedPreferencesManager.keyIsDebug);
    if (_sharedPreferencesManager.isKeyExists(SharedPreferencesManager.keyAccessCode)! && _sharedPreferencesManager.isKeyExists(SharedPreferencesManager.keyBaseUrl)!) {
      baseUrl = U.decodeBase64Url(U.getBaseUrl()!);
      _dio.options.baseUrl = baseUrl + U.decodeBase64Url(Uri.decodeComponent(U.getAccessCode()!));
//      _dio.options.baseUrl = baseUrl + U.getAccessCode();
      _dio.interceptors.add(DioLoggingInterceptors(_dio));
    }
  }

  Future<Token> loginUser(LoginBody loginBody) async {
    try {
      // print("======base url==========");
      // print(baseUrl + U.decryptAESCryptoJS(U.getAccessCode(), U.passphrase));
      var loginData = loginBody.toJson();
      var strData = "";
      var i = 0;
      loginData.forEach((key, value) {
        strData = strData +
            (i == 0 ? '' : '&') +
            key +
            '=' +
            Uri.encodeComponent(value);
        i++;
      });
      // print(strData);
      final response = await _dio.post('/oauth/token?' + strData,
          options: Options(
            headers: {
              'Accept': 'application/json',
              'Authorization': 'Basic ${base64Encode(
                utf8.encode('${kIsWeb?clientIdWeb:clientId}:${kIsWeb?clientSecretWeb:clientSecret}'),
              )}'
            },
          ));
      return Token.fromJson(response.data);
    } on DioException catch (error) {
     // print(error.response);
      if (error.response == null) {
        try {
          final result = await InternetAddress.lookup('google.com');
          if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
            return Token.withError('errorConnection'.tr());
          }
        } on SocketException catch (_) {
          return Token.withError('noInternet'.tr());
        }
      } else if (error.response?.statusCode == 400) {
        if (error.response?.data['error_description'] == 'User account has expired') return Token.withError('expAccount'.tr());
        return Token.withError('invalidLogin'.tr());
      } else if (error.response?.statusCode == 401) {
        if (error.response?.data['error_description'] ==
            'Invalid phone number') {
          return Token.withError('invalidPhone'.tr());
        }
        return Token.withError('expAccount'.tr());
      } else if (error.response!.statusCode! >= 500) {
        return Token.withError('errorConnection'.tr());
      } else {
        return Token.withError('errorServer'.tr());
      }
      return Token.withError('$error');
    }
  }

  Future<Token> refreshAuth(RefreshTokenBody refreshTokenBody) async {
    try {
      // print(refreshTokenBody.toJson());
      var refreshData = refreshTokenBody.toJson();
      var strData = "";
      var i = 0;
      refreshData.forEach((key, value) {
        strData = strData +
            (i == 0 ? '' : '&') +
            key +
            '=' +
            Uri.encodeComponent(value);
        i++;
      });
      // print(strData);
      final response = await _dio.post(
        '/oauth/token?' + strData,
        options: Options(
          headers: {
            'Accept': 'application/json',
            'Authorization': 'Basic ${base64Encode(
              utf8.encode('${kIsWeb?clientIdWeb:clientId}:${kIsWeb?clientSecretWeb:clientSecret}'),
            )}',
          },
        ),
      );
      return Token.fromJson(response.data);
    } on DioException catch (error) {
//      print(error.response.statusCode);
      return Token.withError('$error');
    } catch(error){
      return Token.withError('$error');
    }
  }

  Future<dynamic> getJsonData(String path, var params, context,
      {bool secondCheck = false}) async {
    try {
      Response<String> response = await _dio.getUri(
        Uri(path: path, queryParameters: params),
        options: Options(
          headers: {
            'Accept': 'application/json',
            'requirestoken': true,
          },
        ),
      );
      return json.decode(response.data!);
    } on DioException catch (error) {
      print(error.response);
      if (error.response == null) {
        try {
          final result = await InternetAddress.lookup('google.com');
          if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {

            handlingError(context, 1); //error server
          }
        } on SocketException catch (_) {
          // handlingError(context, ApiError.NO_INTERNET); //no internet
        }
      } else if (error.response!.statusCode! >= 500) {
        if (secondCheck) {
          print('secondCheck');
          handlingError(context, 2); //error connection
        } else {
          await Future.delayed(Duration(milliseconds: 200));
          return getData(path, params, context, secondCheck: true);
        }
        //error server
      } else if (error.response?.statusCode == 401) {
        handlingError(context, 3); //error auth
      } else {
        if (secondCheck) {
          print('secondCheck');
          handlingError(context, 2); //error connection
        } else {
          await Future.delayed(Duration(milliseconds: 200));
          return getData(path, params, context, secondCheck: true);
        }
      }
      return Future.error(error);
    } catch (error) {
      print(error.toString());
      handlingError(context, 1);
      return Future.error(error);
    }
  }

  Future getData(String path, var params, BuildContext context, {bool secondCheck = false}) async {
    try {
      Response<String> response = await _dio.getUri(
        Uri(path: path, queryParameters: params),
        options: Options(
          headers: {
            'requirestoken': true,
          },
        ),
      );
//      print(response.data);
      return json.decode(response.data!);
    } on DioException catch (error) {
      // print(error.response!.statusCode);
      bool isOpen = ModalRoute.of(context)?.isCurrent != true;
      if (error.response == null) {
        try {
          final result = await InternetAddress.lookup('google.com');
          if (!isOpen && result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
            handlingError(context, 1); //error server
          }
        } on SocketException catch (_) {
          // if(!isOpen) handlingError(context, 0); //no internet
        }
      } else if (!isOpen && error.response!.statusCode! >= 500) {
        handlingError(context, 1); //error server
      } else if (!isOpen && error.response?.statusCode == 401) {
        handlingError(context, 3); //error auth
      } else {
        if(!isOpen){
          if (secondCheck) {
            print('secondCheck');
            handlingError(context, 2); //error connection
          } else {
            return getData(path, params, context, secondCheck: true);
          }
        }
      }
      return null;
    }
  }

  Future postData(String path, var params, var data, context) async {
    try {
      Response response = await _dio.postUri(
        Uri(path: path, queryParameters: params),
        data: data,
        options: Options(
          headers: {
            'Accept': 'application/json',
            'requirestoken': true,
          },
        ),
      );
      return response.data;
    } on DioException catch (error) {
     print(error);
      if (error.response == null) {
        try {
          final result = await InternetAddress.lookup('google.com');
          if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
            showError(context, 'errorConnection'.tr());
          }
        } on SocketException catch (_) {
          showError(context, 'noInternet'.tr());
        }
      } else if (error.response!.statusCode! >= 500) {
        showError(context, 'errorConnection'.tr());
      } else if (error.response?.statusCode == 401) {
        handlingError(context, 3); //error auth
      } else if (error.response?.statusCode == 422) {
        if(error.response?.data['message'] == 'Worktime did not found'){
          showError(context, 'notFoundWorktime'.tr());
        } else if(error.response?.data['message'] == 'Cant send broadcast message, you have not permission.'){
          showError(context, 'broadcastPermission'.tr());
        } else if(error.response?.data['message'] == 'Cant send broadcast message, you have not permission.'){
          showError(context, 'broadcastPermission'.tr());
        } else if(error.response?.data['message'] == 'request did not match informant rights'){
          showError(context, 'idNotMatch'.tr().replaceAll("#ID", data['user_id']));
        } else if(error.response?.data['message'] == 'Informant user id not found.'){
          showError(context, 'idNotFound'.tr());
        } else if(error.response?.data['message'] == 'You are not registered as receptionist or room attendant.'){
          showError(context, 'informantNotRegistered'.tr());
        } else {
          showError(context, error.response?.data['message']);
        }
      } else {
        showError(context, 'errorServer'.tr());
      }
      return null;
    }
  }

  Future postDataNoAuth(String path) async {
    try {
      // print(path);
      Response response = await _dio.postUri(Uri(path: path));
      return response.data;
    } on DioException catch (error) {
     print(error.response);
      return null;
    }
  }

  Future patchData(String path, var data, context, {var params}) async {
    try {
      Response response = await _dio.patchUri(
        Uri(path: path, queryParameters: params),
        data: data,
        options: Options(
          headers: {
            'Accept': 'application/json',
            'requirestoken': true,
          },
        ),
      );
      return response.data;
    } on DioException catch (error) {
      if (error.response == null) {
        try {
          final result = await InternetAddress.lookup('google.com');
          if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
            showError(context, 'errorConnection'.tr());
          }
        } on SocketException catch (_) {
          showError(context, 'noInternet'.tr());
        }
      } else if (error.response!.statusCode! >= 500) {
        showError(context, 'errorConnection'.tr());
      } else if (error.response?.statusCode == 401) {
        handlingError(context, 3); //error auth
      } else if (error.response?.statusCode == 422) {
        if (error.response?.data['message'] == 'Old Password Not Match.') {
          showError(context, 'wrongOldPass'.tr());
        } else if (error.response?.data['message'] ==
            'New password already in used.') {
          showError(context, 'alreadyUsePass'.tr());
        } else {
          showError(context, error.response?.data['message']);
        }
      } else {
        showError(context, 'errorServer'.tr());
      }
      return null;
    }
  }

  Future<dynamic> getJsonDataNoAuth(String path, {int n = 0}) async {
    // print('sini');
    var thisUrl = U.decodeBase64Url(U.getBaseUrl()!) + U.decodeBase64Url(Uri.decodeComponent(U.getAccessCode()!));
    // print("url : ${thisUrl + path}");
    try{
      var response = await http.get(Uri.parse(thisUrl + path)).timeout(Duration(seconds: 5));
      // print("data: ${response.body}");
      if(response.statusCode == 200){
        return Future.value(json.decode(response.body));
      }
      else{
        return Future.error(json.decode(response.body));
      }
    } on TimeoutException catch (error) {
      // print("err timeout men");
      // Fluttertoast.showToast(msg: 'invalid_bridge'.tr());
      return Future.error(error);
    } catch (error) {
      // print("err catch: $error");
      if (n < 3) {
        return getJsonDataNoAuth(path, n: n+1);
      } else {
        return Future.error(error);
      }
    }
    // try {
    //   Response<String> response = await _dio.getUri(Uri(path: path));
    //   return json.decode(response.data!);
    // } catch (error) {
    //   if (n < 3) {
    //     print("retry $n");
    //     return getJsonDataNoAuth(path, n: n+1);
    //   } else {
    //     print("return error: after $n trial");
    //     if (path.contains("/api/license")) {
    //       U.clearAccessCode();
    //     }
    //     return Future.error(error);
    //   }
    // }
  }

  Future getDataNoAuth(String path, {int n = 0}) async {
    try {
      Response<String> response = await _dio.getUri(Uri(path: path));
      return json.decode(response.data!);
    } catch (error) {
      // print('trien $n times!');
      if (n < 3) {
        getDataNoAuth(path, n: n+1);
      } else {
        // print("error after trial $n times:  ${error.response}");
        return isDebug ? Future.error(error) : null;
      }
    }
  }

  Future downloadImage(String path, String savePath) async {
    try {
      var response = _dio.download(path, savePath);
      return response;
    } catch (e) {
      return e;
    }
  }

  String getServiceAsset(String key){
    return _dio.options.baseUrl+'/assets/lotties/$key';
  }
}
