import 'package:benchmark_di/scenarios/universal_binding_mode.dart';
import 'package:benchmark_di/scenarios/universal_scenario.dart';
import 'package:benchmark_di/scenarios/universal_service.dart';
import 'package:kiwi/kiwi.dart';
import 'di_adapter.dart';

/// DIAdapter for KiwiContainer with universal benchmark scenario support.
class KiwiAdapter extends DIAdapter<KiwiContainer> {
  late KiwiContainer _container;

  KiwiAdapter({KiwiContainer? container, bool isSubScope = false}) {
    _container = container ?? KiwiContainer();
  }

  @override
  void setupDependencies(void Function(KiwiContainer container) registration) {
    registration(_container);
  }

  @override
  Registration<KiwiContainer> universalRegistration<S extends Enum>({
    required S scenario,
    required int chainCount,
    required int nestingDepth,
    required UniversalBindingMode bindingMode,
  }) {
    if (scenario is UniversalScenario) {
      if (scenario == UniversalScenario.asyncChain ||
          bindingMode == UniversalBindingMode.asyncStrategy) {
        throw UnsupportedError(
            'Kiwi does not support async dependencies or async binding scenarios.');
      }
      return (container) {
        switch (scenario) {
          case UniversalScenario.asyncChain:
            break;
          case UniversalScenario.register:
            container.registerSingleton<UniversalService>(
              (c) => UniversalServiceImpl(value: 'reg', dependency: null),
            );
            break;
          case UniversalScenario.named:
            container.registerFactory<UniversalService>(
                (c) => UniversalServiceImpl(value: 'impl1'),
                name: 'impl1');
            container.registerFactory<UniversalService>(
                (c) => UniversalServiceImpl(value: 'impl2'),
                name: 'impl2');
            break;
          case UniversalScenario.chain:
            for (int chain = 1; chain <= chainCount; chain++) {
              for (int level = 1; level <= nestingDepth; level++) {
                final prevDepName = '${chain}_${level - 1}';
                final depName = '${chain}_$level';
                switch (bindingMode) {
                  case UniversalBindingMode.singletonStrategy:
                  case UniversalBindingMode.lazySingletonStrategy:
                    // Kiwi's registerSingleton is lazy (factory-based, cached on first resolve)
                    container.registerSingleton<UniversalService>(
                        (c) => UniversalServiceImpl(
                            value: depName,
                            dependency: level > 1
                                ? c.resolve<UniversalService>(prevDepName)
                                : null),
                        name: depName);
                    break;
                  case UniversalBindingMode.factoryStrategy:
                    container.registerFactory<UniversalService>(
                        (c) => UniversalServiceImpl(
                            value: depName,
                            dependency: level > 1
                                ? c.resolve<UniversalService>(prevDepName)
                                : null),
                        name: depName);
                    break;
                  case UniversalBindingMode.asyncStrategy:
                    // Not supported
                    break;
                }
              }
            }
            final depName = '${chainCount}_$nestingDepth';
            container.registerSingleton<UniversalService>(
                (c) => c.resolve<UniversalService>(depName));
            break;
          case UniversalScenario.override:
            final depName = '${chainCount}_$nestingDepth';
            container.registerSingleton<UniversalService>(
                (c) => c.resolve<UniversalService>(depName));
            break;
        }
      };
    }
    throw UnsupportedError('Scenario $scenario not supported by KiwiAdapter');
  }

  @override
  T resolve<T extends Object>({String? named}) {
    return _container.resolve<T>(named);
  }

  @override
  Future<T> resolveAsync<T extends Object>({String? named}) {
    return Future.value(_container.resolve<T>(named));
  }

  @override
  void teardown() {
    _container.clear();
  }

  @override
  KiwiAdapter openSubScope(String name) {
    // Returns a new scoped container. Inheritance not implemented.
    return KiwiAdapter(container: KiwiContainer.scoped(), isSubScope: true);
  }

  @override
  Future<void> waitForAsyncReady() async {}
}
