import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:baseproject/core/common/message.dart';
import 'package:baseproject/core/language/app_localizations.dart';
import 'package:baseproject/features/presentation/app/view/app.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_datetime_picker_plus/flutter_datetime_picker_plus.dart';
import 'package:intl/intl.dart';
import 'package:url_launcher/url_launcher.dart';

import 'package:path/path.dart' as p;

class Utils {
  static int dateDiffToSeconds(DateTime date1, DateTime date2) {
    return date1.difference(date2).inSeconds;
  }

  static int dateDiffToDays(DateTime date1, DateTime date2) {
    return date1.difference(date2).inDays;
  }

  static int dateDiffToYears(DateTime date1, DateTime date2) {
    return date1.year - date2.year;
  }

  static Map<String, dynamic> convertObjectToMap(Object object) {
    final Map<String, dynamic> temp = jsonDecode(jsonEncode(object)) as Map<String, dynamic>;
    // print(temp);
    return temp;
  }

  static int getCharacterCode(String character) {
    final List<int> codeUnits = character.codeUnits;
    int temp = 65;
    if (codeUnits.isNotEmpty) temp = codeUnits[0];
    return temp;
  }

  static String thumbnailImage(String url, {double? width, double? height, String mode = 'crop'}) {
    // if (url.startsWith("http")) return url;
    // if (url.contains(mode)) return url;
    // // ignore: parameter_assignments
    // if (width == double.infinity || width == null) width = 0;

    // // ignore: parameter_assignments
    // if (height == double.infinity || height == null) height = 0;

    // if (width == 0 && height == 0) return url;

    // final List<StorageServer>? storageServer = GetIt.I<AppSettings>().getAppSettings.storageServers;
    // if (storageServer != null) {
    //   final Iterable<String> allStorage = storageServer.map((StorageServer e) => e.publicDomain);
    //   for (String item in allStorage) {
    //     if (url.toLowerCase().contains(item.toLowerCase())) {
    //       if (item[item.length - 1] != '/') item = item + "/";
    //       // ignore: parameter_assignments
    //       url = url.replaceAll(item.toLowerCase(),
    //           '$item${(width != null && width > 0) ? width.toInt() * 2 : 0}x${(height != null && height > 0) ? height.toInt() * 2 : 0}/${mode}/');
    //     }
    //   }
    // }

    return url;
  }

  static T enumFromString<T>(Iterable<T> values, String value) {
    // ignore: always_specify_types
    return values.firstWhere((type) => type.toString().split(".").last == value, orElse: () => values.first);
  }

  LocaleType getLocaleType() {
    return Utils.enumFromString<LocaleType>(
        LocaleType.values, AppLocalizations.of(navigatorKey!.currentState!.context)!.locale.languageCode);
  }

  Future<DateTime?> onShowDatePicker(
      {required BuildContext context,
      DateTime? currentValue,
      DateTime? firstDate,
      DateTime? maxDate,
      bool isShowAfter = true}) {
    final DateTime _currentValue = currentValue != null && currentValue.year > 0 ? currentValue : DateTime.now();
    final DateTime _minDate = !isShowAfter ? DateTime.now() : firstDate ?? DateTime(1900);
    if (Platform.isIOS) {
      return DatePicker.showDatePicker(
        context,
        minTime: _minDate,
        maxTime: maxDate ?? DateTime(2100),
        currentTime: _currentValue,
        locale: getLocaleType(),
      );
    }

    return showDatePicker(
      context: context,
      initialDate: _currentValue,
      firstDate: _minDate,
      lastDate: maxDate ?? DateTime(2100),
      currentDate: currentValue,
    );
  }

  Future<TimeOfDay?> onShowTimePicker(BuildContext context, DateTime? currentValue, {bool isShowSecond = false}) async {
    final DateTime? _currentValue = (currentValue?.hour ?? 0) > 0 ? currentValue : DateTime.now();
    if (Platform.isIOS) {
      final DateTime? result = await DatePicker.showTimePicker(
        context,
        showSecondsColumn: isShowSecond,
        currentTime: _currentValue,
        locale: getLocaleType(),
      );

      if (result == null) return null;
      return TimeOfDay.fromDateTime(result);
    }

    final TimeOfDay? timePickerResult = await showTimePicker(
      context: context,
      initialTime: currentValue != null ? TimeOfDay.fromDateTime(currentValue) : TimeOfDay.fromDateTime(DateTime.now()),
    );
    return timePickerResult ?? (currentValue != null ? TimeOfDay.fromDateTime(currentValue) : null);
  }

  static T? getPropertyValueByName<T>(Object? object, String propertyName) {
    if (object == null) return null;
    try {
      final Map<String, dynamic> temp = convertObjectToMap(object);
      return temp[propertyName] as T;
    } catch (ex) {
      return null;
    }
  }

  static String getExtension(String path) {
    return p.extension(path).replaceAll(".", "");
  }

  static String getExtensionWithDot(String path) {
    return p.extension(path);
  }

  static String getFileName(String path) {
    return p.basename(path);
  }

  static String getFileNameWithoutExtension(String path) {
    return p.basenameWithoutExtension(path);
  }

  static String getFileNameFromTime(String extension) {
    return DateTime.now().millisecondsSinceEpoch.toString() + "." + extension;
  }

  static T? getRouterObject<T>(Object? arguments, {int index = -1}) {
    if (arguments == null) return null;
    if (index >= 0) {
      final List<dynamic> args = arguments as List<dynamic>;
      if (index < args.length) {
        return (args[index]) != null ? args[index] as T : null;
      } else {
        return null;
      }
    }

    return arguments as T;
  }

  static String? getRouterObjectString(Object? arguments, {int index = -1}) {
    if (arguments == null) return null;
    if (index >= 0) {
      final List<dynamic> args = arguments as List<dynamic>;
      if (index < args.length) {
        return (args[index]) != null ? args[index] as String : null;
      } else {
        return null;
      }
    }

    return arguments as String?;
  }

  static Map<String, dynamic> base64ToMap(String b64) {
    return json.decode(base64Decode(b64));
  }

  static String base64Decode(String b64) {
    final String foo = b64.split('.')[0];
    final List<int> res = base64.decode(base64.normalize(foo));
    return utf8.decode(res);
  }

  Future<FilePickerResult?> openChooseFiles({
    FileType type = FileType.any,
    List<String>? allowedExtensions = const <String>["doc", "pdf", "mp4", "mp3"],
    Function(FilePickerStatus)? onFileLoading,
    bool allowCompression = true,
    bool allowMultiple = false,
    bool withData = false,
    bool withReadStream = false,
  }) async {
    // final AppSettings _appSettings = GetIt.I<AppSettings>();
    final FilePickerResult? result = await FilePicker.platform.pickFiles(
        type: FileType.custom,
        allowedExtensions: allowedExtensions,
        allowMultiple: allowMultiple,
        allowCompression: allowCompression,
        onFileLoading: onFileLoading,
        withData: withData,
        withReadStream: withReadStream);
    if (result != null) {
      double _fileSize = 0;
      for (final PlatformFile filePath in result.files) {
        _fileSize += _getSizeFile(filePath.path ?? '');
      }
      if (_fileSize < 15) {
        //_appSettings.configs.maximumFileSizeUpload.first.document
        return result;
      } else {
        showErrorMessage(AppLocalizations.of(navigatorKey!.currentState!.context)!
            .translate('Tệp tin vượt quá dung lượng cho phép: ${15} mb'));
        return null;
      }
    } else {
      return null;
    }
  }

  double _getSizeFile(String filePath) {
    final File _file = File(filePath);
    final int sizeInBytes = _file.lengthSync();
    return sizeInBytes / (1024 * 1024);
  }

  static Future<void> launchPhone({String value = ""}) async {
    String url = 'tel:$value';
    final uri = Uri.parse(url);
    if (await canLaunchUrl(uri)) {
      await launchUrl(
        uri,
      );
    } else {
      showErrorMessage("Không có ứng dụng phù hợp");
    }
  }

  static Future<void> launchEmail({String value = ""}) async {
    String url = 'mailto:$value';
    final uri = Uri.parse(url);
    if (await canLaunchUrl(uri)) {
      await launchUrl(
        uri,
      );
    } else {
      showErrorMessage("Không có ứng dụng phù hợp");
    }
  }

  static DateTime getDate(DateTime time) {
    return DateTime(time.year, time.month, time.day);
  }

  static DateTime getToDate(DateTime time) {
    return DateTime(time.year, time.month, time.day).add(const Duration(days: 1)).add(const Duration(seconds: -1));
  }

  static DateTime addMonth(DateTime date) {
    var year = date.year + ((date.month + 1) ~/ 12);
    var month = (date.month + 1) % 12;
    if (month == 0) month = 12;
    var day = date.day;

    // Adjust day if the result is an invalid date, e.g., adding a month to January 31st
    if (day > 28) {
      day = min(day, DateTime(year, month + 1, 0).day);
    }

    return DateTime(year, month, day, date.hour, date.minute, date.second, date.millisecond, date.microsecond);
  }

  static DateTime? getDateTimeFromUTC(DateTime? time) {
    if (time == null) return null;
    if (!time.isUtc) return time;
    return time.toLocal();
  }

  static int getTimeSpanFromTime(String time) {
    try {
      final now = DateTime.now();
      final temps = time.split(":").map((e) => e.trim()).toList();
      return DateTime(
        now.year,
        now.month,
        now.day,
        int.parse(temps[0]),
        int.parse(temps[1]),
      ).millisecondsSinceEpoch;
    } catch (e) {
      return 0;
    }
  }

  static DateTime? getDateFromText(String stringTime, {String stringFormat = "MM/dd/yyyy hh:mm:ss"}) {
    try {
      DateFormat format = DateFormat(stringFormat);
      DateTime dateTime = format.parse(stringTime);
      return dateTime;
    } catch (e) {
      return null;
    }
  }

  static String fileSize(double size) {
    double d1 = size / 1024.0;
    double d2 = d1 / 1024.0;
    double d3 = d2 / 1024.0;
    if (size < 1024.0) {
      return size.toString() + " bytes";
    }
    if (d1 < 1024.0) {
      return d1.round().toString() + " KB";
    }
    if (d2 < 1024.0) {
      return d2.round().toString() + " MB";
    }
    return d3.round().toString() + " GB";
  }

  static Future<void> openLaunch(String link,
      {mode = LaunchMode.externalApplication, String appStoreLink = "", bool isOpenAppWebView = false}) async {
    if (isOpenAppWebView) {
    } else {
      final uri = Uri.parse(link);
      if (await canLaunchUrl(uri)) {
        await launchUrl(
          uri,
          mode: mode,
        );
      } else {
        if (appStoreLink.isNotEmpty) {
          await launchUrl(Uri.parse(appStoreLink), mode: mode);
        }
        //throw 'Could not launch $link';
      }
    }
  }

  // static Future<void> _launchURL(Uri link) async {
  //   try {
  //     await ct.launchUrl(
  //       link,
  //       customTabsOptions: ct.CustomTabsOptions(
  //         // colorSchemes: ct.CustomTabsColorSchemes.defaults(
  //         //   toolbarColor: theme.colorScheme.surface,
  //         // ),
  //         shareState: ct.CustomTabsShareState.on,
  //         urlBarHidingEnabled: true,
  //         showTitle: true,
  //         closeButton: ct.CustomTabsCloseButton(
  //           icon: 'ic_action_close',
  //         ),
  //       ),
  //       // safariVCOptions: SafariViewControllerOptions(
  //       //   preferredBarTintColor: theme.colorScheme.surface,
  //       //   preferredControlTintColor: theme.colorScheme.onSurface,
  //       //   barCollapsingEnabled: true,
  //       //   dismissButtonStyle: SafariViewControllerDismissButtonStyle.close,
  //       // ),
  //     );
  //   } catch (e) {
  //     // If the URL launch fails, an exception will be thrown. (For example, if no browser app is installed on the Android device.)
  //     debugPrint(e.toString());
  //   }
  // }

  static String getFormatTime(int number) {
    String textTimeFormat = "";
    if (number > 3600) {
      final int hours = (number ~/ 3600).round();
      final int minutes = ((number % 3600) / 60).round();
      final int seconds = ((number % 3600) % 60).round();
      textTimeFormat = hours.toString() +
          ' giờ ' +
          (minutes != 0 ? minutes.toString() + ' phút ' : '') +
          (seconds != 0 ? seconds.toString() + ' giây' : '');
    } else {
      if (number >= 60) {
        final int minutes = (number ~/ 60).round();
        final int seconds = number % 60;
        textTimeFormat = minutes.toString() + ' phút ' + (seconds != 0 ? seconds.toString() + ' giây' : '');
      } else {
        textTimeFormat = number.toString() + ' giây';
      }
    }
    return textTimeFormat;
  }

  static paginate<T>(List<T> array, int pageSize, int pageNumber) {
    return array.sublist(
        (pageNumber - 1) * pageSize, (pageNumber * pageSize) > array.length ? array.length : pageNumber * pageSize);
  }

  // static Future<bool> checkVersionOff() async {
  //   // if (kDebugMode) return false;
  //   final configs = getItSuper<AppSettings>().appSettings.configs;
  //   if (configs.schoolVersionAppOffRegister == null) return false;

  //   final List<String> listVersionEnable =
  //       configs.schoolVersionAppOffRegister!.map((VersionModel e) => e.version).toList();
  //   final String currentVersion = await PackageInfo.fromPlatform().then((PackageInfo value) => value.version);
  //   return listVersionEnable.firstWhere((String element) => element == currentVersion, orElse: () => '').isNotEmpty &&
  //       Platform.isIOS;
  // }
}
