import 'package:flutter/widgets.dart';

/// App 启动初始化器
///
/// 两阶段串行队列，确保启动流畅、资源不竞争。
///
/// ## 为什么不能在 initState 里一股脑 await？
///
/// 初始化任务并发执行会导致：
/// - 多个 await 阻塞首帧渲染 → 白屏时间长
/// - 任务间资源竞争（网络、IO、CPU）→ 互相拖慢
/// - 一个任务失败可能阻塞后续所有任务
///
/// ## 解决方案：两阶段 + 串行队列
///
/// ```
/// App 启动
///   │
///   ├── Phase 1: Critical（initState 中同步触发）
///   │   串行执行，必须在用户交互前完成。
///   │   只放真正阻塞用户操作的任务（尽量少）。
///   │   例：网络监听（后续所有网络操作依赖它）
///   │
///   ├── 首帧渲染（用户看到 UI）
///   │
///   └── Phase 2: Deferred（addPostFrameCallback 触发）
///       串行执行，首帧渲染后逐个跑。
///       不争抢资源，不影响 UI 流畅度。
///       例：推送注册、缓存预热、埋点 SDK 初始化
/// ```
///
/// ## 添加新任务的规则
///
/// 问自己：「这个任务不完成，用户能正常看到首页吗？」
/// - **能** → 放 deferred（绝大多数情况）
/// - **不能** → 放 critical（谨慎添加，每多一个都会拖慢启动）
///
/// ## 设计原则
///
/// - **串行不并发**：同阶段内任务按顺序逐个执行，避免资源竞争
/// - **隔离不传染**：每个任务独立 try-catch，一个失败不阻塞后续
/// - **可观测**：每个任务计时 + 日志，方便排查启动瓶颈
/// - **首帧优先**：deferred 阶段等首帧渲染完再开始
class AppInitializer {
  /// 关键任务（首帧前串行执行）
  final List<InitTask> critical;

  /// 延迟任务（首帧后串行执行）
  final List<InitTask> deferred;

  /// 日志回调
  final void Function(String message, {String? tag})? onLog;

  const AppInitializer({
    this.critical = const [],
    this.deferred = const [],
    this.onLog,
  });

  /// 启动初始化
  ///
  /// 1. 立即串行执行 critical 任务
  /// 2. 注册 addPostFrameCallback，首帧后串行执行 deferred 任务
  ///
  /// 在 initState 中调用（fire-and-forget，不 await）。
  void run() {
    _runCritical();
  }

  /// 执行关键阶段
  Future<void> _runCritical() async {
    if (critical.isEmpty) {
      _log('No critical tasks');
    } else {
      _log('── Critical phase: ${critical.length} task(s) ──');
      final totalSw = Stopwatch()..start();

      await _runTasksSequentially(critical);

      totalSw.stop();
      _log('── Critical phase done in ${totalSw.elapsedMilliseconds}ms ──');
    }

    // 关键阶段完成后，注册首帧回调执行延迟阶段
    _scheduleDeferredPhase();
  }

  /// 注册 addPostFrameCallback
  ///
  /// 需要在 critical 完成后再注册，确保顺序：
  /// critical 完成 → 首帧渲染 → deferred 开始
  void _scheduleDeferredPhase() {
    if (deferred.isEmpty) return;

    WidgetsBinding.instance.addPostFrameCallback((_) => _runDeferred());
  }

  /// 执行延迟阶段
  Future<void> _runDeferred() async {
    _log('── Deferred phase: ${deferred.length} task(s) ──');
    final totalSw = Stopwatch()..start();

    await _runTasksSequentially(deferred);

    totalSw.stop();
    _log('── Deferred phase done in ${totalSw.elapsedMilliseconds}ms ──');
  }

  /// 串行执行任务队列
  ///
  /// 逐个 await，不并发。每个任务独立 try-catch + 计时。
  Future<void> _runTasksSequentially(List<InitTask> tasks) async {
    for (var i = 0; i < tasks.length; i++) {
      final task = tasks[i];
      final sw = Stopwatch()..start();

      try {
        _log('[${i + 1}/${tasks.length}] ${task.name} ...');
        await task.task();
        sw.stop();
        _log('[${i + 1}/${tasks.length}] ${task.name} done (${sw.elapsedMilliseconds}ms)');
      } catch (e) {
        sw.stop();
        _log('[${i + 1}/${tasks.length}] ${task.name} FAILED (${sw.elapsedMilliseconds}ms): $e');
        // 不 rethrow — 隔离失败，继续执行后续任务
      }
    }
  }

  void _log(String message) {
    onLog?.call(message, tag: 'AppInit');
  }
}

/// 初始化任务
class InitTask {
  /// 任务名称（用于日志）
  final String name;

  /// 任务执行体
  final Future<void> Function() task;

  const InitTask({
    required this.name,
    required this.task,
  });
}
