part of '../di_providers.dart';


final playbackResolverProvider = FutureProvider<PlaybackResolver>((ref) async {
  final gateway = await ref.read(embyGatewayProvider.future);
  final deviceId = await ref.read(deviceIdProvider.future);
  return PlaybackResolver(
    gateway: gateway,
    deviceId: deviceId,
    deviceName: kEmbyDeviceName,
  );
});

typedef _EmbyDeps = ({
  SessionRepository session,
  ServerRepository server,
  EmbyGateway gw,
});

Future<_EmbyDeps> _embyDeps(Ref ref) async => (
  session: await ref.watch(sessionRepositoryProvider.future),
  server: await ref.watch(serverRepositoryProvider.future),
  gw: await ref.watch(embyGatewayProvider.future),
);


FutureProvider<T> _authedUseCaseProvider<T>(
  T Function({
    required SessionRepository sessionRepository,
    required ServerRepository serverRepository,
    required EmbyGateway embyGateway,
  })
  ctor,
) {
  return FutureProvider<T>((ref) async {
    final d = await _embyDeps(ref);
    return ctor(
      sessionRepository: d.session,
      serverRepository: d.server,
      embyGateway: d.gw,
    );
  });
}

final listServersUseCaseProvider = FutureProvider<ListServersUseCase>((
  ref,
) async {
  final repo = await ref.watch(serverRepositoryProvider.future);
  return ListServersUseCase(serverRepository: repo);
});

final saveServerUseCaseProvider = FutureProvider<SaveServerUseCase>((
  ref,
) async {
  final repo = await ref.watch(serverRepositoryProvider.future);
  return SaveServerUseCase(serverRepository: repo);
});

final reorderServersUseCaseProvider = FutureProvider<ReorderServersUseCase>((
  ref,
) async {
  final repo = await ref.watch(serverRepositoryProvider.future);
  return ReorderServersUseCase(serverRepository: repo);
});

final probeServerUseCaseProvider = FutureProvider<ProbeServerUseCase>((
  ref,
) async {
  final gw = await ref.watch(embyGatewayProvider.future);
  return ProbeServerUseCase(embyGateway: gw);
});

final exportBackupUseCaseProvider = FutureProvider<ExportBackupUseCase>((
  ref,
) async {
  return ExportBackupUseCase(
    serverRepository: await ref.watch(serverRepositoryProvider.future),
    sessionRepository: await ref.watch(sessionRepositoryProvider.future),
    danmakuSourcesStore: ref.read(danmakuSourcesStoreProvider),
    scriptWidgetRepository: await ref.watch(
      scriptWidgetRepositoryProvider.future,
    ),
  );
});

final importBackupUseCaseProvider = FutureProvider<ImportBackupUseCase>((
  ref,
) async {
  return ImportBackupUseCase(
    serverRepository: await ref.watch(serverRepositoryProvider.future),
    sessionRepository: await ref.watch(sessionRepositoryProvider.future),
    danmakuSourcesStore: ref.read(danmakuSourcesStoreProvider),
    scriptWidgetRepository: await ref.watch(
      scriptWidgetRepositoryProvider.future,
    ),
  );
});


final serverSyncGatewayProvider = Provider<ServerSyncGateway>(
  (ref) => ServerSyncClient(),
);


final uploadServerSyncUseCaseProvider = FutureProvider<UploadServerSyncUseCase>(
  (ref) async {
    return UploadServerSyncUseCase(
      export: await ref.watch(exportBackupUseCaseProvider.future),
      gateway: ref.read(serverSyncGatewayProvider),
    );
  },
);


final pullServerSyncUseCaseProvider = FutureProvider<PullServerSyncUseCase>((
  ref,
) async {
  return PullServerSyncUseCase(
    serverRepository: await ref.watch(serverRepositoryProvider.future),
    sessionRepository: await ref.watch(sessionRepositoryProvider.future),
    danmakuSourcesStore: ref.read(danmakuSourcesStoreProvider),
    scriptWidgetRepository: await ref.watch(
      scriptWidgetRepositoryProvider.future,
    ),
    gateway: ref.read(serverSyncGatewayProvider),
  );
});


final repairSessionsUseCaseProvider = FutureProvider<RepairSessionsUseCase>((
  ref,
) async {
  final d = await _embyDeps(ref);
  return RepairSessionsUseCase(
    serverRepository: d.server,
    sessionRepository: d.session,
    embyGateway: d.gw,
  );
});

final deleteServerUseCaseProvider = FutureProvider<DeleteServerUseCase>((
  ref,
) async {
  final sRepo = await ref.watch(serverRepositoryProvider.future);
  final ssRepo = await ref.watch(sessionRepositoryProvider.future);
  return DeleteServerUseCase(
    serverRepository: sRepo,
    sessionRepository: ssRepo,
  );
});

final togglePauseServerUseCaseProvider =
    FutureProvider<TogglePauseServerUseCase>((ref) async {
      final sRepo = await ref.watch(serverRepositoryProvider.future);
      return TogglePauseServerUseCase(serverRepository: sRepo);
    });

final authByNameUseCaseProvider = FutureProvider<AuthByNameUseCase>((
  ref,
) async {
  final d = await _embyDeps(ref);
  return AuthByNameUseCase(
    serverRepository: d.server,
    sessionRepository: d.session,
    embyGateway: d.gw,
  );
});

final logoutUseCaseProvider = FutureProvider<LogoutUseCase>((ref) async {
  return LogoutUseCase(
    sessionRepository: await ref.watch(sessionRepositoryProvider.future),
  );
});

final listSessionsUseCaseProvider = FutureProvider<ListSessionsUseCase>((
  ref,
) async {
  return ListSessionsUseCase(
    sessionRepository: await ref.watch(sessionRepositoryProvider.future),
    serverRepository: await ref.watch(serverRepositoryProvider.future),
  );
});

final switchSessionUseCaseProvider = FutureProvider<SwitchSessionUseCase>((
  ref,
) async {
  return SwitchSessionUseCase(
    sessionRepository: await ref.watch(sessionRepositoryProvider.future),
  );
});

final changePasswordUseCaseProvider = FutureProvider<ChangePasswordUseCase>((
  ref,
) async {
  final d = await _embyDeps(ref);
  return ChangePasswordUseCase(
    sessionRepository: d.session,
    serverRepository: d.server,
    embyGateway: d.gw,
  );
});

final libraryViewsUseCaseProvider = _authedUseCaseProvider(
  GetLibraryViewsUseCase.new,
);
final libraryResumeUseCaseProvider = _authedUseCaseProvider(
  GetLibraryResumeUseCase.new,
);
final libraryLatestUseCaseProvider = _authedUseCaseProvider(
  GetLibraryLatestUseCase.new,
);
final libraryItemsUseCaseProvider = _authedUseCaseProvider(
  GetLibraryItemsUseCase.new,
);
final homeBannerUseCaseProvider = _authedUseCaseProvider(
  GetHomeBannerUseCase.new,
);
final mediaDetailUseCaseProvider = _authedUseCaseProvider(
  GetMediaDetailUseCase.new,
);
final setFavoriteUseCaseProvider = _authedUseCaseProvider(
  SetFavoriteUseCase.new,
);
final setPlayedUseCaseProvider = _authedUseCaseProvider(SetPlayedUseCase.new);
final hideFromResumeUseCaseProvider = _authedUseCaseProvider(
  HideFromResumeUseCase.new,
);
final seriesEpisodesUseCaseProvider = _authedUseCaseProvider(
  GetSeriesEpisodesUseCase.new,
);
final seriesSeasonsUseCaseProvider = _authedUseCaseProvider(
  GetSeriesSeasonsUseCase.new,
);
final similarItemsUseCaseProvider = _authedUseCaseProvider(
  GetSimilarItemsUseCase.new,
);
final additionalPartsUseCaseProvider = _authedUseCaseProvider(
  GetAdditionalPartsUseCase.new,
);
final specialFeaturesUseCaseProvider = _authedUseCaseProvider(
  GetSpecialFeaturesUseCase.new,
);
final crossServerSearchUseCaseProvider = _authedUseCaseProvider(
  CrossServerSearchUseCase.new,
);
final tmdbAvailabilityUseCaseProvider = _authedUseCaseProvider(
  TmdbAvailabilityUseCase.new,
);

final globalKeywordSearchUseCaseProvider = _authedUseCaseProvider(
  GlobalKeywordSearchUseCase.new,
);
final aggregatedResumeUseCaseProvider = _authedUseCaseProvider(
  GetAggregatedResumeUseCase.new,
);
final aggregatedFavoritesUseCaseProvider = _authedUseCaseProvider(
  GetAggregatedFavoritesUseCase.new,
);
final aggregatedRecentUseCaseProvider = _authedUseCaseProvider(
  GetAggregatedRecentUseCase.new,
);
