import 'dart:math';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter/services.dart';

int getRandomWithNum(int min, int max) {
  if (max < min) {
    // 保护性处理：交换或抛错，这里交换
    final tmp = min;
    min = max;
    max = tmp;
  }
  final random = Random();
  return random.nextInt(max - min + 1) + min; // 生成 [min, max] 的随机数
}

double screenHeight(BuildContext context) {
  double screenHeight = MediaQuery.of(context).size.height;
  return screenHeight;
}
double screenWidth(BuildContext context) {
  double screenWidth = MediaQuery.of(context).size.width;
  return screenWidth;
}
Future<T?> pushPage<T>(Widget page, BuildContext context) {
  return Navigator.push<T>(
    context,
    MaterialPageRoute(builder: (_) => page),
  );
}
void present(Widget page, BuildContext context) {
  Navigator.of(context).push(
    PageRouteBuilder(
      pageBuilder: (context, animation, secondaryAnimation) => page,
      transitionDuration: Duration.zero,
      reverseTransitionDuration: Duration.zero,
    ),
  );
}
void presentOpaque(Widget page, BuildContext context) {
  Navigator.of(context).push(
    PageRouteBuilder(
      opaque: false, // 允许下层透出
      barrierColor: Colors.black.withOpacity(0.5), //路由遮罩色
      pageBuilder: (context, animation, secondaryAnimation) => page,
      transitionDuration: Duration.zero,
      reverseTransitionDuration: Duration.zero,
    ),
  );
}

class FocusHelper {
  static final FocusNode _emptyNode = FocusNode();
  /// 延迟一帧后再移交焦点，避免不生效的问题
  static void clearFocus(BuildContext context) {
    WidgetsBinding.instance.addPostFrameCallback((_) async {
      FocusScope.of(context).requestFocus(_emptyNode);
      await SystemChannels.textInput.invokeMethod('TextInput.hide');
    });
  }
}

/// 文本样式工具类，返回 Text Widget
class HhTextStyleUtils {
  /// 主要标题，返回 Text
  /// [text]: 文本内容
  /// [color]: 文本颜色，默认黑色
  /// [fontSize]: 字体大小，默认16.0
  /// [bold]: 是否加粗，默认true
  static Text mainTitle(
    String text, {
    Color color = Colors.black,
    double fontSize = 14.0,
    bool bold = true,
  }) {
    return Text(
      text,
      style: TextStyle(
        color: color,
        fontSize: fontSize,
        fontWeight: bold ? FontWeight.bold : FontWeight.normal,
      ),
    );
  }

  static TextStyle secondaryTitleStyle = TextStyle(
    color: Colors.black54,
    fontSize: 13.0,
  );

  /// 次要标题，返回 Text
  /// [text]: 文本内容
  /// [color]: 文本颜色，默认深灰
  /// [fontSize]: 字体大小，默认14.0
  /// [bold]: 是否加粗，默认false
  static Text secondaryTitle(
    String text, {
    Color color = Colors.black54,
    double fontSize = 12.0,
    bool bold = false,
  }) {
    return Text(
      text,
      style: TextStyle(
        color: color,
        fontSize: fontSize,
        fontWeight: bold ? FontWeight.bold : FontWeight.normal,
      ),
    );
  }

  /// 小文字，返回 Text
  /// [text]: 文本内容
  /// [color]: 文本颜色，默认灰色
  /// [fontSize]: 字体大小，默认12.0
  /// [bold]: 是否加粗，默认false
  static Text smallText(
    String text, {
    Color color = Colors.black54,
    double fontSize = 11.0,
    bool bold = false,
  }) {
    return Text(
      text,
      style: TextStyle(
        color: color,
        fontSize: fontSize,
        fontWeight: bold ? FontWeight.bold : FontWeight.normal,
      ),
    );
  }
}

/// 版本信息模型类
class AppVersionInfo {
  final String versionName; // 版本名称（如 1.0.0）
  final String buildNumber; // 构建号（如 1）
  final String fullVersion; // 完整版本（如 1.0.0+1）

  AppVersionInfo({
    required this.versionName,
    required this.buildNumber,
    required this.fullVersion,
  });

  @override
  String toString() {
    return fullVersion;
  }
}

// 获取应用版本信息的方法
Future<AppVersionInfo> getAppVersion() async {
  try {
    final packageInfo = await PackageInfo.fromPlatform();
    return AppVersionInfo(
      versionName: packageInfo.version,
      buildNumber: packageInfo.buildNumber,
      fullVersion: '${packageInfo.version}+${packageInfo.buildNumber}',
    );
  } catch (e) {
    // 获取失败时返回默认值
    return AppVersionInfo(
      versionName: '1.0.0',
      buildNumber: '1',
      fullVersion: '1.0.0+0',
    );
  }
}

/// ------------------------------------------------------
/// 全局会话管理
/// ------------------------------------------------------
class SessionService {
  SessionService._();

  static final SessionService instance = SessionService._();

  String? corpinfoId;
  String? loginUserId;
  Map<String, dynamic>? loginUser;
  String? deptId;
  String? deptLevel;
  String? postId;
  String? username;
  String? version;
  String? basePath;
  String? isRest;
  List<dynamic>? permission;
  bool updateInfo = false;
  String? dangerJson;
  String? riskJson;
  String? departmentJsonStr;
  String? departmentHiddenTypeJsonStr;
  String? customRecordDangerJson;
  String? unqualifiedInspectionItemID;
  String? listItemNameJson;
  String? studyToken;



  /// 如果以下任何一项为空，则跳转到登录页
  void loginSession(BuildContext context) {
    if (corpinfoId == null || loginUserId == null || loginUser == null) {
      Navigator.pushReplacementNamed(context, '/login');
    }
  }

  // setters
  void setLoginUser(Map<String, dynamic> user) => loginUser = user;
  void setStudyToken(String token) => studyToken = token;

  void setLoginUserId(String id) => loginUserId = id;

  void setCorpinfoId(String id) => corpinfoId = id;

  void setDeptId(String id) => deptId = id;

  void setDeptLevel(String level) => deptLevel = level;

  void setPostId(String id) => postId = id;

  void setUsername(String name) => username = name;

  void setVersion(String ver) => version = ver;

  void setBasePath(String url) => basePath = url;

  void setIsRest(String rest) => isRest = rest;

  void setPermission(List<dynamic> list) => permission = list;

  void setUpdateInfo(bool flag) => updateInfo = flag;

  void setDangerWaitInfo(String json) => dangerJson = json;

  void setRiskWaitInfo(String json) => riskJson = json;

  void setDepartmentJsonStr(String json) => departmentJsonStr = json;

  void setCustomRecordDangerJson(String json) => customRecordDangerJson = json;

  void setUnqualifiedInspectionItemIDJson(String json) => unqualifiedInspectionItemID = json;

  void setListItemNameJson(String json) => listItemNameJson = json;

}

/// ------------------------------------------------------
/// 日期格式化
/// ------------------------------------------------------
String formatDate(DateTime? date, String fmt) {
  if (date == null) return '';
  String twoDigits(int n) => n.toString().padLeft(2, '0');

  final replacements = <String, String>{
    'yyyy': date.year.toString(),
    'yy': date.year.toString().substring(2),
    'MM': twoDigits(date.month),
    'M': date.month.toString(),
    'dd': twoDigits(date.day),
    'd': date.day.toString(),
    'hh': twoDigits(date.hour),
    'h': date.hour.toString(),
    'mm': twoDigits(date.minute),
    'm': date.minute.toString(),
    'ss': twoDigits(date.second),
    's': date.second.toString(),
  };

  String result = fmt;
  replacements.forEach((key, value) {
    result = result.replaceAllMapped(RegExp(key), (_) => value);
  });
  return result;
}
/// 把 'yyyy-MM-dd HH:mm'（或 'yyyy-MM-ddTHH:mm'）解析为 DateTime，失败返回 null
DateTime? _parseYMdHm(String s) {
  if (s.isEmpty) return null;
  // 允许传入 'yyyy-MM-dd HH:mm' 或 'yyyy-MM-ddTHH:mm'
  // 如果没有秒，补上 :00
  String t = s.trim();
  // 如果只有日期部分，直接返回 null（你也可以自行扩展）
  if (!RegExp(r'^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}$').hasMatch(t)) {
    // 试着容错：如果是 'yyyy-MM-dd HH:mm:ss' 也接受
    if (!RegExp(r'^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}$').hasMatch(t)) {
      return null;
    } else {
      // 已经带秒，直接 parse
      return DateTime.tryParse(t.replaceFirst(' ', 'T'));
    }
  }
  // 如果是 'yyyy-MM-dd HH:mm'，补齐秒并使用 ISO 格式
  final iso = t.replaceFirst(' ', 'T') + ':00';
  return DateTime.tryParse(iso);
}

/// 比较两个 'yyyy-MM-dd HH:mm' 格式字符串
/// 返回 1 (a>b), 0 (a==b), -1 (a<b)
int compareYMdHmStrings(String a, String b) {
  final da = _parseYMdHm(a);
  final db = _parseYMdHm(b);

  if (da == null || db == null) {
    throw FormatException("时间格式错误，期望 'yyyy-MM-dd HH:mm' 或 'yyyy-MM-dd HH:mm:ss'");
  }

  if (da.isAtSameMomentAs(db)) return 0;
  return da.isAfter(db) ? 1 : -1;
}
/// 便捷：a 是否 晚于 b
bool isAfterStr(String a, String b) => compareYMdHmStrings(a, b) == 1;

/// 便捷：a 是否 早于 b
bool isBeforeStr(String a, String b) => compareYMdHmStrings(a, b) == -1;

/// ------------------------------------------------------
/// 防多次点击
/// ------------------------------------------------------
class ClickUtil {
  ClickUtil._();

  static bool _canClick = true;

  /// 调用示例：
  /// ClickUtil.noMultipleClicks(() { /* your code */ });
  static void noMultipleClicks(VoidCallback fn, {int delayMs = 2000}) {
    if (_canClick) {
      _canClick = false;
      fn();
      Future.delayed(Duration(milliseconds: delayMs), () {
        _canClick = true;
      });
    } else {
      debugPrint('请稍后点击');
    }
  }
}

void presentPage(BuildContext context, Widget page) {
  Navigator.push(
    context,
    MaterialPageRoute(fullscreenDialog: true, builder: (_) => page),
  );
}
class LoadingDialogHelper {
  static Timer? _timer;

  /// 显示加载框（带超时，默认 10 秒）
  static void show({String? message, Duration timeout = const Duration(seconds: 10)}) {
    // 先清理上一个计时器，避免重复
    _timer?.cancel();

    if (message != null) {
      EasyLoading.show(status: message);
    } else {
      EasyLoading.show();
    }

    // 设置超时自动隐藏
    _timer = Timer(timeout, () {
      // 保护性调用 dismiss（避免访问不存在的 isShow）
      try {
        EasyLoading.dismiss();
      } catch (e) {
        debugPrint('EasyLoading.dismiss error: $e');
      }
      _timer?.cancel();
      _timer = null;
    });
  }

  /// 隐藏加载框（手动触发）
  static void hide() {
    // 清理计时器
    _timer?.cancel();
    _timer = null;

    try {
      EasyLoading.dismiss();
    } catch (e) {
      debugPrint('EasyLoading.dismiss error: $e');
    }
  }
}


/// 将秒数转换为 “HH:MM:SS” 格式
String secondsCount(dynamic seconds) {
  // 先尝试解析出一个 double 值
  double totalSeconds;
  if (seconds == null) {
    totalSeconds = 0;
  } else if (seconds is num) {
    totalSeconds = seconds.toDouble();
  } else {
    // seconds 是字符串或其他，尝试 parse
    totalSeconds = double.tryParse(seconds.toString()) ?? 0.0;
  }

  // 取整秒，向下取整
  final int secs = totalSeconds.floor();

  final int h = (secs ~/ 3600) % 24;
  final int m = (secs ~/ 60) % 60;
  final int s = secs % 60;

  // padLeft 保证两位数
  final String hh = h.toString().padLeft(2, '0');
  final String mm = m.toString().padLeft(2, '0');
  final String ss = s.toString().padLeft(2, '0');

  return '$hh:$mm:$ss';
}
void printLongString(String text, {int chunkSize = 800}) {
  final pattern = RegExp('.{1,$chunkSize}'); // 每 chunkSize 个字符一组
  for (final match in pattern.allMatches(text)) {
    print(match.group(0));
  }
}

/// 表单处理
class FormUtils {
  /// 判断 [data] 中的 [key] 是否存在“有效值”：
  /// - key 不存在或值为 null -> false
  /// - String：去掉首尾空白后非空 -> true
  /// - Iterable / Map：非空 -> true
  /// - 其它类型（int、double、bool 等）只要不为 null 就算有值 -> true
  static bool hasValue(Map<String, dynamic> data, String key) {
    if (!data.containsKey(key)) return false;
    final val = data[key];
    if (val == null) return false;

    if (val is String) {
      return val.trim().isNotEmpty;
    }
    if (val is Iterable || val is Map) {
      return val.isNotEmpty;
    }
    // 数字、布尔等其它非空即可
    return true;
  }
  /// 在list中根据一个 key，value，找到对应的map
  static Map findMapForKeyValue(List list,String key, String value) {
    Map target = list.firstWhere(
          (item) => item[key] == value,
      orElse: () => {},
    );
    return target ?? {};
  }
}

class NoDataWidget {
  static Widget show() {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Image.asset('assets/images/null.png', width: 200,),
          Text('暂无数据', style: TextStyle(color: Colors.grey)),
        ],
      ),
    );
  }

}
class NativeOrientation {
  static const MethodChannel _channel = MethodChannel('app.orientation');

  static Future<bool> setLandscape() async {
    try {
      final res = await _channel.invokeMethod('setOrientation', 'landscape');
      return res == true;
    } on PlatformException catch (e) {
      debugPrint('PlatformException setLandscape: $e');
      return false;
    } catch (e) {
      debugPrint('Unknown error setLandscape: $e');
      return false;
    }
  }

  static Future<bool> setPortrait() async {
    try {
      final res = await _channel.invokeMethod('setOrientation', 'portrait');
      return res == true;
    } on PlatformException catch (e) {
      debugPrint('PlatformException setPortrait: $e');
      return false;
    } catch (e) {
      debugPrint('Unknown error setPortrait: $e');
      return false;
    }
  }
}
