import 'package:easy_localization/easy_localization.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_randomcolor/flutter_randomcolor.dart';
import 'package:flutter_svg/svg.dart';
import 'package:jwt_decoder/jwt_decoder.dart';
import 'package:telnow_mobile_new/src/api/api_auth_repository.dart';
import 'package:telnow_mobile_new/src/model/token/token.dart';
import 'dart:convert';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:telnow_mobile_new/src/api/api_auth_provider.dart';
import 'package:telnow_mobile_new/src/api/jwt_token.dart';
import 'package:telnow_mobile_new/src/injector/injector.dart';
import 'package:telnow_mobile_new/src/model/refreshtoken/refresh_token_body.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:synchronized/synchronized.dart';

import 'cache_manager.dart';

const Color backgroundColor = Colors.white;
const Color primaryColor = Color(0xff078C84);
const Color secondaryColor = Color(0xffCC6029);
const Color textColor = Color(0xff292D32);
const Color disabledColor = Color(0xff989696);

class U {
  static final String passphrase = "telmessenger-key";
  static final SharedPreferencesManager _sharedPreferencesManager = locator<SharedPreferencesManager>();
  static dynamic _license;
  static dynamic _userData;
  static String rawPid = '';
  static String _url = '';
  static bool _hasChangedPassword = true;
  static bool _loadAfterRequest = false;
  static bool? _connected;
  static bool _notifPermission = false;
  static bool _notifPermissionDismissed = false;

  // static final ApiAuthProvider _apiAuthProvider = ApiAuthProvider();
  static final Codec<String, String> stringToBase64Url = utf8.fuse(base64Url);
  static final JwtToken token = JwtToken();

  static final _lockAuth = Lock();
  static int _authLastMs = 0;
  static Token? _lastReqToken;

  static final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

  static const AndroidNotificationChannel channel = AndroidNotificationChannel(
    'notification_channel', // id
    'Normal Notification', // title
    description: 'This channel is used for normal notifications.', // description
    importance: Importance.high,
    enableLights: true,
    playSound: true,
    sound: RawResourceAndroidNotificationSound('notification_alarm'),
  );

  // =
  // FlutterLocalNotificationsPlugin();

  static Future<Token?> _tryRefreshAuth(RefreshTokenBody refreshTokenBody,
      {int n = 0}) async {
    ApiAuthRepository apiAuthRepository = ApiAuthRepository();
    try {
      Token token = await apiAuthRepository.postRefreshAuth(refreshTokenBody);
      await _sharedPreferencesManager.putString(
          SharedPreferencesManager.keyAccessToken, token.accessToken!);
      await _sharedPreferencesManager.putString(
          SharedPreferencesManager.keyRefreshToken, token.refreshToken!);

      return Future.value(token);
    } catch (error) {
      if (n < 3) {
        return _tryRefreshAuth(refreshTokenBody, n: n++);
      } else {
        await _sharedPreferencesManager.putString(
            SharedPreferencesManager.keyAccessToken, '');
        await _sharedPreferencesManager.putString(
            SharedPreferencesManager.keyRefreshToken, '');
        Future.error(error);
      }
    }
  }

  static Future waitForRefreshAuth() async {
    if(JwtDecoder.isExpired(_sharedPreferencesManager.getString(SharedPreferencesManager.keyAccessToken)!)){
      // print("get new token");
      String? refreshToken = _sharedPreferencesManager.getString(SharedPreferencesManager.keyRefreshToken)!;
      RefreshTokenBody? refreshTokenBody = RefreshTokenBody('refresh_token', refreshToken);
      refreshAuth(refreshTokenBody);
    } else {
      print(JwtDecoder.getRemainingTime(_sharedPreferencesManager.getString(SharedPreferencesManager.keyAccessToken)!));
    }
    // return _lockAuth.synchronized(() async {
    //   print("wait refresh token OK");
    // });
  }

  static Future<Token?> refreshAuth(RefreshTokenBody refreshTokenBody) async {
    // print("refresh token");
    // return _lockAuth.synchronized(() async { //lock bikin stuck
      // print("refresh token start");
      var nw = DateTime.now().millisecondsSinceEpoch;
      if (_authLastMs == 0 || nw - _authLastMs >= 5000) {
        // print("refresh token request");
        ApiAuthRepository apiAuthRepository = ApiAuthRepository();
        var token = await _tryRefreshAuth(refreshTokenBody);
        _authLastMs = DateTime.now().millisecondsSinceEpoch;
        _lastReqToken = token;
      }
      // print("refresh token finish");
      return _lastReqToken;
    // });

    // if (token != null) {
    //   _authLastMs = DateTime.now().millisecondsSinceEpoch;
    //   _lastReqToken = token;
    // }
    // print("refresh token finish");

    // return Future.value(_lastReqToken);
  }

  static Future <String?> getFcmToken() async {
    // print("minta fcm nya");
    if (_sharedPreferencesManager.getString(SharedPreferencesManager.keyFcmToken) != "" && _sharedPreferencesManager.getString(SharedPreferencesManager.keyFcmToken) != null) {
      // print("return shared aja");
      return _sharedPreferencesManager.getString(SharedPreferencesManager.keyFcmToken);
    } else {
      try {
        var token = await FirebaseMessaging.instance.getToken();
        if (token != null) {
          _sharedPreferencesManager.putString(SharedPreferencesManager.keyFcmToken, token);
          // print("token from U: $token");
          return token;
        }
      } catch(e) {
        print(e.toString());
        return null;
      }
    }
    return null;
  }

  static void clearUserData() {
    _userData = null;
  }

  static void clearLicenseData() {
    _license = null;
  }

  static void setNotifPermission(value) {
    _notifPermission = value;
  }

  static getNotifPermission(){
    return _notifPermission;
  }

  static void setNotifPermissionDismissed(value) {
    _notifPermissionDismissed = value;
  }

  static getNotifPermissionDismissed(){
    return _notifPermissionDismissed;
  }

  static void savePreferences(token) async {
    // print('save preferences!');
    await _sharedPreferencesManager.putString(SharedPreferencesManager.keyAccessToken, token.accessToken);
    await _sharedPreferencesManager.putString(SharedPreferencesManager.keyRefreshToken, token.refreshToken);
    await _sharedPreferencesManager.putInt(SharedPreferencesManager.keyCountRefreshToken, 0);
  }

  static Future<bool> clearPreferences() async {
    await _sharedPreferencesManager.clearKey(SharedPreferencesManager.keyAccessToken);
    await _sharedPreferencesManager.clearKey(SharedPreferencesManager.keyRefreshToken);
    await _sharedPreferencesManager.clearKey(SharedPreferencesManager.keyUsername);
    await _sharedPreferencesManager.clearKey(SharedPreferencesManager.keyIsLogin);
    await _sharedPreferencesManager.clearKey(SharedPreferencesManager.keyScoope);
    await _sharedPreferencesManager.clearKey(SharedPreferencesManager.debugString);
    await _sharedPreferencesManager.clearKey(SharedPreferencesManager.keyMenuDisplay);
    return true;
  }

  static setChangedPassword(val) async {
    _hasChangedPassword = val;
  }

  static bool getChangedPassword() {
    return _hasChangedPassword;
  }

  static setInternetStatus(val) async {
    _connected = val;
  }

  static bool getInternetStatus() {
    return _connected??true;
  }

  static setLoadAfterRequest(val) async {
    _loadAfterRequest = val;
  }

  static bool getLoadAfterRequest() {
    return _loadAfterRequest;
  }

  static Future<dynamic> getUserData(context) async {
    if (_userData == null) {
      try {
        _userData = await token.getUserData(context);
      } catch (error) {
        print(error.toString());
        U.showDebugToast(error.toString());
        return Future.error(error);
      }
    }

    return Future.value(_userData);
  }

  static Future<dynamic> reloadLicense() async {
    _license = null;
    return getLicense();
  }

  static Future<dynamic>? getLicense({showErr = true}) async {
    if (_license == null) {
      try {
        var dt = await ApiAuthProvider().getJsonDataNoAuth('/api/license');
        _license = dt;
      } catch (error) {
        if(showErr){
          Fluttertoast.showToast(msg: 'invalid_bridge'.tr());
        }
        // print(error.toString());
        // U.showDebugToast(error.toString());
        return Future.error(error);
      }
    }

    return Future.value(_license);
  }

  static bool? isDebug() {
    return _sharedPreferencesManager.getBool(SharedPreferencesManager.keyIsDebug);
  }

  static bool? isLoggedIn() {
    return _sharedPreferencesManager.getBool(SharedPreferencesManager.keyIsLogin) != null ? _sharedPreferencesManager.getBool(SharedPreferencesManager.keyIsLogin) : false;
  }

  static int? getVersion() {
    return _sharedPreferencesManager.getInt(SharedPreferencesManager.version);
  }

  static String? getAccessCode() {
    return _sharedPreferencesManager.getString(SharedPreferencesManager.keyAccessCode) == null || _sharedPreferencesManager.getString(SharedPreferencesManager.keyAccessCode) == '' ? null :
    _sharedPreferencesManager.getString(SharedPreferencesManager.keyAccessCode)!.contains("=") ?
    Uri.encodeComponent(_sharedPreferencesManager.getString(SharedPreferencesManager.keyAccessCode)!) :
    _sharedPreferencesManager.getString(SharedPreferencesManager.keyAccessCode);
  }

  static String? getBaseUrl() {
    return _sharedPreferencesManager.getString(SharedPreferencesManager.keyBaseUrl);
  }

  static bool servantDisplay() {
    if(_sharedPreferencesManager.isKeyExists(SharedPreferencesManager.keyMenuDisplay)!){
      return _sharedPreferencesManager.getBool(SharedPreferencesManager.keyMenuDisplay)!;
    }
    return false;
  }

  static void setServantDisplay(bool servant) async {
    await _sharedPreferencesManager.putBool(SharedPreferencesManager.keyMenuDisplay, servant);
  }

  static bool autoTranslate() {
    if(_sharedPreferencesManager.isKeyExists(SharedPreferencesManager.keyAutoTranslate)!){
      return _sharedPreferencesManager.getBool(SharedPreferencesManager.keyAutoTranslate)!;
    }
    return false;
  }

  static void setAutoTranslate(bool translate) async {
    await _sharedPreferencesManager.putBool(SharedPreferencesManager.keyAutoTranslate, translate);
  }

  static void clearAccessCode() async {
    // print("accCode cleared!!");
    await _sharedPreferencesManager.clearKey(SharedPreferencesManager.keyAccessCode);
    return;
  }

  static String? getSerialCode() {
    return _sharedPreferencesManager.getString(SharedPreferencesManager.keySerialCode);
  }

  static int _serverVersion = 0;
  static getServerVersion() async{
    String url = '/api/license';
    try {
      var dt = await ApiAuthProvider().getJsonDataNoAuth(url);
      _serverVersion = dt['serverVersion'];
      CacheMan.writeData(url, _serverVersion);
    } catch (error) {
      var val = await CacheMan.readData(url);
      if (val != null) {
        _serverVersion = val['data'];
      }
      // print("U checkServerVersion error: ${error.toString()}");
    }
    // print('checking current server version: $_serverVersion');
  }

  static newServerVersion(int version){
    return version <= _serverVersion;
  }

  static int retServerVersion(){
    return _serverVersion;
  }

  static Map _otherLabelList = {};
  static getOtherLabelList(BuildContext context) async{
    if(newServerVersion(1725245109)){
      var res = await ApiAuthProvider().getData('/api/systemSettings/search/additional', {'key': 'request-for-other'}, context);
      if(res != null){
        _otherLabelList = res;
      }
    }
  }

  static otherLabelList(){
    return _otherLabelList;
  }

  static void showDebugToast(String msg) {
    if (_sharedPreferencesManager.getBool(SharedPreferencesManager.keyIsDebug)!) {
      Fluttertoast.showToast(
          msg: "Debug:" + msg,
          toastLength: Toast.LENGTH_SHORT,
          gravity: ToastGravity.BOTTOM,
          timeInSecForIosWeb: 1,
          backgroundColor: Colors.red,
          textColor: Colors.white,
          fontSize: 16.0);
    }
  }

  static double bodyWidth(context) {
    var width = MediaQuery.of(context).size.width;
    var height = MediaQuery.of(context).size.height;

    var portrait = !(width * 3 / 4 > height);
    var bodyWidth = portrait ? width : width / 2;

    if (bodyWidth < 500) {
      if (width < 500) {
        bodyWidth = width;
      } else {
        bodyWidth = 500;
      }
    }

    return bodyWidth;
  }

  static bool webView(BuildContext context){
    if(kIsWeb && MediaQuery.of(context).size.width >= 1000){
      return true;
    }
    return false;
  }

  static String rewriteUrl(String encrypted){
    var targetString = encrypted;
    if(encrypted.contains('/')){
      targetString = encrypted.split("/").first;
    }
    var baseUrl = decodeBase64Url(targetString);
    if(!baseUrl.contains('https://') && !baseUrl.contains('http://')){
      if(baseUrl.contains('://')){
        baseUrl = 'https://'+(baseUrl.split('://')[1]);
      }
      else{
        baseUrl = 'https://'+baseUrl;
      }
    }

    if(baseUrl.substring(baseUrl.length - 1) != '/'){
      baseUrl = baseUrl+'/';
    }
// print(baseUrl);
    return encodeBase64Url(baseUrl);
  }

  static String encodeBase64Url(String encrypted){
    try {
      return stringToBase64Url.encode(encrypted);
    } catch (error) {
      throw error;
    }
  }

  static String decodeBase64Url(String encrypted){
    try {
      return stringToBase64Url.decode(encrypted);
    } catch (error) {
      throw error;
    }
  }

  static String getUrl() {
    return _url;
  }

  static void setUrl(String url) async {
    _url = url;
    return;
  }

  static void clearUrl() {
    _url = "";
  }

  static String getPidFromUrl(String url){
    // print("U => url : $url");
    if (url.contains("/loginme")) {
      url = url.split("/loginme").first;
    }
    if (!url.contains("=")) {
      url = Uri.decodeComponent(url);
    }
    url = url.replaceAll('/app/', '');

    // if(url.contains('#')){
    //   return Uri.encodeComponent(url);
    // }

    return Uri.encodeComponent(url.split('/').first);
  }

  static List<Color> defaultRainbowColors() {
      return [
        Colors.red,
        Colors.orange,
        Colors.yellow,
        Colors.green,
        Colors.blue,
        Colors.indigo,
        Colors.purple,
      ];
  }

  static Widget iconsax(String name, {Color color = Colors.black, double size = 24}){
    return SvgPicture.asset(
      'assets/iconsax/${name}.svg',
      colorFilter: ColorFilter.mode(color, BlendMode.srcIn),
      width: size, height: size,
      fit: BoxFit.scaleDown
    );
  }

  static Options options = Options(format: Format.hex, luminosity: Luminosity.dark, colorType: [ColorType.red, ColorType.green, ColorType.blue, ColorType.orange]);
  static Map<String, dynamic> colorList = {};
  static int getColor(String name){
    try {
      if(!colorList.containsKey(name)){
        var color;
        do{
          color = int.parse(RandomColor.getColor(options).replaceAll('#', '0xff'));
        }while(colorList.containsValue(color));
        colorList[name] = color;
      }
      return colorList[name];
    } catch (e) {
      return 0xff000000;
    }
  }

  static String langColumn(BuildContext context, String text){
    var code = context.locale.toString();
    return code == 'id' ? text : '$text${code[0].toUpperCase()}${code.substring(1).toLowerCase()}';
  }

  static bool hidePayload = false;
  static void setHidePayload(value) {
    hidePayload = value;
  }

  static checkPendingRequest(BuildContext context)async{
    List list = _sharedPreferencesManager.isKeyExists(SharedPreferencesManager.keyPendingData)!?jsonDecode(_sharedPreferencesManager.getString(SharedPreferencesManager.keyPendingData)!):[];
    List uniqueId = [];
    if(list.length > 0){
      showLoading(context);
      for(var element in list){
        var data = element['data'];
        if(element['others']){
          data['req'][0]['uniqueId'] = element['uniqueId'];
          data['req'][0]['images'] = element['imageList'];
          var res = await ApiAuthProvider().postData('/api/receptionists/send/request', null, data, context);
          if (res != null) {
            uniqueId.add(res['uniqueId']);
            // print('success send pending request others');
          }
        }
        else{
          data['uniqueId'] = element['uniqueId'];
          data['images'] = element['imageList'];
          var res = await ApiAuthProvider().postData('/api/requestHistories/search/request/' + element['type'] + '/' + element['id'].toString() + '/' + element['noteFormat'] + '/submit', null, data, context);
          if (res != null) {
            uniqueId.add(res['uniqueId']);
            // print('success send pending request');
          }
        }
      }

      uniqueId.forEach((id) {
        list.removeWhere((li) => li['uniqueId'] == id);
      });
      await _sharedPreferencesManager.putString(SharedPreferencesManager.keyPendingData, jsonEncode(list));
      closeLoading(context);
    }
  }
  
  static String renderStatus(String currentState){
    String title = '';

    if (currentState == 'DIPROSES') {
      title = 'stateRequested'.tr();
    } else if (currentState == 'DIMULAI') {
      title = 'stateDone'.tr();
    } else if (currentState == 'DISELESAIKAN' || currentState == 'TUNTAS') {
      title = 'stateFinish'.tr();
    } else if (currentState == 'DIBATALKAN') {
      title = 'stateCanceled'.tr();
    }
    
    return title;
  }
}

//@optionalTypeArgs
// abstract class State<T extends StatefulWidget>
@optionalTypeArgs
abstract class SaveState<T extends StatefulWidget> extends State<T> {
  bool _disposed = false;

  @override
  void dispose() {
    _disposed = true;
    super.dispose();
  }

  @override
  void setState(VoidCallback fn) {
    if (!mounted || _disposed) {
      return;
    }
    super.setState(fn);
  }
}
