import 'package:flutter/foundation.dart';
import 'package:lanebow/services/event_bus.dart';
import 'package:lanebow/utils/test_utils.dart';
import 'package:lanebow/utils/test_config.dart';

/// EventBus 테스트 환경 유틸리티
/// - 개별 테스트 파일에서 간단히 호출하여 격리/정리 보장
/// - 기존 EventBus의 setCurrentTestId/reset/tearDown 루틴을 안전하게 래핑
class EventBusTestUtils {
  /// 테스트 전용: 테스트 ID를 설정하고 인스턴스를 초기화
  static Future<void> setUp(String testId) async {
    assert(TestUtils.isInTest, 'EventBusTestUtils.setUp는 테스트 환경에서만 호출하세요.');
    // 테스트 설정 로깅(선택)
    if (kDebugMode || TestConfig.instance.isVerboseLogging) {
      debugPrint('[EB-Test] setUp: testId=$testId');
    }

    EventBus.setCurrentTestId(testId);
    // 마이크로태스크 소진으로 초기화 안정화
    await Future.microtask(() {});
    await Future.microtask(() {});
  }

  /// 테스트 종료: 현재 테스트 ID 기반 인스턴스 dispose 및 환경 해제
  static Future<void> tearDown() async {
    assert(TestUtils.isInTest, 'EventBusTestUtils.tearDown는 테스트 환경에서만 호출하세요.');
    if (kDebugMode || TestConfig.instance.isVerboseLogging) {
      debugPrint('[EB-Test] tearDown: start');
    }

    // 현재 테스트 인스턴스 dispose 및 환경 해제
    await EventBus.tearDownTestEnvironment();

    // 모든 테스트 인스턴스 정리(안전망)
    await EventBus.resetAllTestInstances();

    // 비동기 작업 완료 보장
    await Future.microtask(() {});
    await Future.microtask(() {});
    // 잔여 타이머/스트림 플러시 대기 (플래키 방지)
    await Future<void>.delayed(const Duration(milliseconds: 700));

    if (kDebugMode || TestConfig.instance.isVerboseLogging) {
      debugPrint('[EB-Test] tearDown: done');
    }
  }

  /// EventBus 관련 비동기 리소스가 idle이 되도록 보장
  static Future<void> waitForIdle() async {
    // EventBus 내부 ensureAllTimersComplete는 private이므로 microtask로 대기
    await Future.microtask(() {});
    await Future.microtask(() {});
    await Future<void>.delayed(const Duration(milliseconds: 100));
  }

  /// 편의 헬퍼: 테스트 파일에서 간단히 등록해 사용
  /// 예)
  ///   setUp(() async => EventBusTestUtils.setUp('member_service_test'));
  ///   tearDown(() async => EventBusTestUtils.tearDown());
  static void registerIn(
    Function(Future<void> Function() fn) setUpCallback,
    Function(Future<void> Function() fn) tearDownCallback, {
    required String testId,
  }) {
    setUpCallback(() async {
      await setUp(testId);
    });
    tearDownCallback(() async {
      await tearDown();
    });
  }
}
