import 'package:ntp/ntp.dart';
import 'package:system_clock/system_clock.dart';

import 'log/logger.dart';

class NtpTimeService {
  static const String TAG = 'NtpTimeService';
  static final NtpTimeService _instance = NtpTimeService._internal();

  factory NtpTimeService() => _instance;

  NtpTimeService._internal();

  // 国内外NTP服务器列表
  static const List<String> _ntpServers = [
    // 国内服务器
    'time.cloudflare.com',
    'pool.ntp.org',
    'time.google.com',
    'time.nist.gov',
    'ntp.aliyun.com',
    'ntp1.aliyun.com',
    'ntp2.aliyun.com',
    'ntp.tencent.com',
    'time1.cloud.tencent.com',
    'time2.cloud.tencent.com',
    'time3.cloud.tencent.com',
    'ntp.ntsc.ac.cn',
    'cn.pool.ntp.org',
    'time.windows.com',
    'time.apple.com',
    'time-a-g.nist.gov',
    'time-b-g.nist.gov',
    'time-c-g.nist.gov',
    'time-d-g.nist.gov',
    'time-e-g.nist.gov',
    'time-a-wwv.nist.gov',
    'time-b-wwv.nist.gov',
    'time-c-wwv.nist.gov',
    'time-d-wwv.nist.gov',
    'time-e-wwv.nist.gov',
    'time-a-b.nist.gov',
    'time-b-b.nist.gov',
    'time-c-b.nist.gov',
    'time-d-b.nist.gov',
    'time-e-b.nist.gov',
  ];

  DateTime? _ntpInitialTime;
  Duration? _elapsedRealtimeInitial;
  String? _currentServer;

  bool get isInitialized =>
      _ntpInitialTime != null && _elapsedRealtimeInitial != null;
  String? get currentServer => _currentServer;

  /// 初始化：从多个NTP服务器获取时间，并记录系统启动时间
  Future<bool> initialize() async {
    try {
      log(TAG, 'NTP time calibrator initialization begins...');
      // 尝试多个NTP服务器
      for (final server in _ntpServers) {
        try {
          log(TAG, 'Try to connect to the NTP server: $server');
          // 加上请求的时间
          final requestTime = DateTime.now();
          _ntpInitialTime = await NTP.now(lookUpAddress: server);
          final responseTime = DateTime.now();
          final requestDuration = responseTime.difference(requestTime);
          log(TAG, 'Request time: ${requestTime.toIso8601String()}');
          log(TAG, 'Response time: ${responseTime.toIso8601String()}');
          log(
            TAG,
            'Request time-consuming: ${requestDuration.inMilliseconds}ms',
          );
          _ntpInitialTime = _ntpInitialTime?.add(requestDuration);
          _elapsedRealtimeInitial = SystemClock.elapsedRealtime();
          _currentServer = server;

          log(TAG, 'NTP time calibration is successful, server: $server');
          log(TAG, 'Initial time of NTP: $_ntpInitialTime');
          log(TAG, 'System start-up time: $_elapsedRealtimeInitial');
          log(TAG, 'Current time: ${DateTime.now().toIso8601String()}');

          return true;
        } catch (e) {
          log(TAG, 'NTP server $server connection failed: $e');
          continue;
        }
      }

      log(TAG, 'All NTP server connection failed, using system time');
      return false;
    } catch (e) {
      log(TAG, 'NTP time calibrator initialization abnormality: $e');
      return false;
    }
  }

  /// 获取当前"网络时间"，通过系统运行时间 + NTP 差值计算
  DateTime getCurrentTime() {
    if (!isInitialized) return DateTime.now();
    final currentElapsedRealtime = SystemClock.elapsedRealtime();
    final elapsed = currentElapsedRealtime - _elapsedRealtimeInitial!;
    return _ntpInitialTime!.add(elapsed);
  }

  /// 获取当前时间戳（毫秒）
  int getCurrentTimestamp() {
    final currentTime = getCurrentTime();
    return currentTime.millisecondsSinceEpoch;
  }

  int getNtpInitialTime() {
    if (!isInitialized) {
      return DateTime.now().millisecondsSinceEpoch;
    }
    return _ntpInitialTime?.millisecondsSinceEpoch ??
        DateTime.now().millisecondsSinceEpoch;
  }

  int getElapsedRealtimeInitial() {
    if (!isInitialized) {
      return SystemClock.elapsedRealtime().inMilliseconds;
    }
    return _elapsedRealtimeInitial?.inMilliseconds ??
        SystemClock.elapsedRealtime().inMilliseconds;
  }

  /// 同步一次 NTP，重新校准
  Future<bool> resync() async {
    try {
      if (isInitialized) {
        return true;
      }
      log(TAG, 'Start resynchronizing NTP time...');
      return await initialize();
    } catch (e) {
      log(TAG, 'Resynchronization of NTP time failed: $e');
      return false;
    }
  }
}
