import 'dart:async';

import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../core/domain/usecases/usecase_helpers.dart';
import '../core/infra/emby_api/playback_resolver.dart';
import '../shared/utils/app_logger.dart';
import 'di_providers.dart';

const _tag = 'PlaybackInfoPrefetch';

typedef PlaybackInfoPrefetchKey = ({
  String serverId,
  String itemId,
  String? mediaSourceId,
  int startTimeTicks,
});

typedef PlaybackInfoPrefetchPayload = ({
  String serverId,
  String itemId,
  String? mediaSourceId,
  int startTimeTicks,
  Map<String, dynamic> info,
});

String describePlaybackInfoPrefetchKey(PlaybackInfoPrefetchKey key) {
  return 'serverId=${key.serverId} itemId=${key.itemId} '
      'mediaSourceId=${key.mediaSourceId ?? '-'} '
      'startTimeTicks=${key.startTimeTicks}';
}

final playbackInfoPrefetchProvider = FutureProvider.autoDispose
    .family<PlaybackInfoPrefetchPayload?, PlaybackInfoPrefetchKey>((
      ref,
      key,
    ) async {
      final keepAlive = ref.keepAlive();
      Timer? cacheTimer;
      var disposed = false;
      ref.onDispose(() {
        disposed = true;
        cacheTimer?.cancel();
      });
      try {
        AppLogger.debug(
          _tag,
          'fetch start ${describePlaybackInfoPrefetchKey(key)}',
        );
        final gateway = await ref.read(embyGatewayProvider.future);
        final sessionRepo = await ref.read(sessionRepositoryProvider.future);
        final serverRepo = await ref.read(serverRepositoryProvider.future);
        final ctx = await resolveAuthedContextForServer(
          sessionRepository: sessionRepo,
          serverRepository: serverRepo,
          serverId: key.serverId,
        );
        if (ctx == null) {
          AppLogger.debug(
            _tag,
            'fetch skipped missing auth ${describePlaybackInfoPrefetchKey(key)}',
          );
          return null;
        }
        final info = await gateway.fetchPlaybackInfo(
          ctx: ctx,
          itemId: key.itemId,
          mediaSourceId: key.mediaSourceId,
          startTimeTicks: key.startTimeTicks,
          isPlayback: true,
          deviceProfile: PlaybackResolver.deviceProfile(),
        );
        if (info.isEmpty) {
          AppLogger.debug(
            _tag,
            'fetch empty ${describePlaybackInfoPrefetchKey(key)}',
          );
          return null;
        }
        AppLogger.debug(
          _tag,
          'fetch success ${describePlaybackInfoPrefetchKey(key)} '
          'payloadKeys=${info.length}',
        );
        return (
          serverId: key.serverId,
          itemId: key.itemId,
          mediaSourceId: key.mediaSourceId,
          startTimeTicks: key.startTimeTicks,
          info: info,
        );
      } catch (e) {
        AppLogger.debug(
          _tag,
          'fetch failed ${describePlaybackInfoPrefetchKey(key)}',
          e,
        );
        return null;
      } finally {
        if (!disposed) {
          cacheTimer = Timer(const Duration(minutes: 2), keepAlive.close);
        }
      }
    });
