part of '../di_providers.dart';


final traktGatewayProvider = Provider<TraktGateway>((ref) => TraktApiClient());


final traktTokenStoreProvider = Provider<TraktTokenStore>(
  (ref) => TraktTokenStore(),
);


final traktAuthProvider = Provider<TraktAuth>((ref) {
  return TraktAuth(
    store: ref.read(traktTokenStoreProvider),
    gateway: ref.read(traktGatewayProvider),
  );
});


final authedTraktGatewayProvider = Provider<AuthedTraktGateway>((ref) {
  return AuthedTraktClient(auth: ref.read(traktAuthProvider));
});


final traktSyncQueueProvider = FutureProvider<TraktPendingSyncQueue>((
  ref,
) async {
  final dir = await ref.watch(appDataDirProvider.future);
  return TraktPendingSyncQueue(
    store: JsonTraktSyncJobStore(
      file: File('${dir.path}/trakt_pending_sync_queue.json'),
    ),
    sender: ref.read(authedTraktGatewayProvider),
    policy: TraktRetryPolicy(),
  );
});


final traktSyncServiceProvider = FutureProvider<TraktSyncService>((ref) async {
  final queue = await ref.read(traktSyncQueueProvider.future);
  return TraktSyncService(
    traktGateway: ref.read(authedTraktGatewayProvider),
    queue: queue,
  );
});


final traktContinueWatchingProvider =
    FutureProvider<List<TraktContinueWatchingItem>>((ref) async {
      final authed = ref.read(authedTraktGatewayProvider);
      if (!await authed.isConnected()) return const [];

      final ready = await ref.watch(_tmdbReadyProvider.future);
      if (ready == null) return const [];

      final List<Map<String, dynamic>> raw;
      try {
        raw = await authed.fetchPlayback();
      } catch (e) {
        AppLogger.warn('Trakt', 'fetchPlayback failed', e);
        return const [];
      }

      final entries = raw
          .map(TraktPlaybackEntry.fromJson)
          .whereType<TraktPlaybackEntry>()
          .toList();
      entries.sort((a, b) {
        final pa = a.pausedAt;
        final pb = b.pausedAt;
        if (pa == null && pb == null) return 0;
        if (pa == null) return 1;
        if (pb == null) return -1;
        return pb.compareTo(pa);
      });

      final base = <TraktContinueWatchingItem>[];
      final seenKeys = <String>{};
      for (final e in entries) {
        final item = TraktContinueWatchingItem.fromEntry(e);
        if (item == null) continue;
        if (!seenKeys.add('${item.mediaType}:${item.tmdbId}')) continue;
        base.add(item);
        if (base.length >= 20) break;
      }
      if (base.isEmpty) return const [];

      const enrichConcurrency = 5;
      final gateway = ref.read(tmdbGatewayProvider);
      final enriched = <TraktContinueWatchingItem>[];
      for (var i = 0; i < base.length; i += enrichConcurrency) {
        final chunk = base.skip(i).take(enrichConcurrency);
        final results = await Future.wait(
          chunk.map((it) async {
            try {
              final detail = await gateway.getMediaDetail(
                ready.config,
                it.tmdbId.toString(),
                it.mediaType,
                language: ready.language,
              );
              final localized = detail?.title;
              final titled = (localized != null && localized.isNotEmpty)
                  ? it.withTitle(localized)
                  : it;
              final url = TmdbImageUrl.backdrop(
                ready.config.imageBaseUrl,
                detail?.backdropPath,
                size: 'w780',
              );
              return titled.withBackdrop(url);
            } catch (_) {
              return it;
            }
          }),
        );
        enriched.addAll(results);
      }

      return enriched;
    });
