import '../../../core/contracts/danmaku.dart';
import '../../../core/contracts/library.dart';
import '../../../core/contracts/playback.dart';
import '../../../providers/audio_settings_provider.dart';
import '../../../providers/danmaku_settings_provider.dart';
import '../../../providers/player_settings_provider.dart';
import '../../../providers/subtitle_settings_provider.dart';
import 'playback_target.dart';

String playbackMemoryKey({
  required String serverId,
  required String userId,
  required String itemId,
  String? seriesId,
}) => '$serverId:$userId:${seriesId ?? itemId}';


class PlaybackRequest {
  final String itemId;
  final String? mediaSourceId;
  final int? startPositionTicks;

  final int? preferredSubtitleStreamIndex;
  final int? preferredAudioStreamIndex;


  final SubtitleStyleSettings subtitleSettings;
  final PlayerSettingsState playerSettings;
  final DanmakuSettingsState danmakuSettings;
  final AudioSettingsState audioSettings;


  final bool playFromStart;


  final PlaybackServerIdentity? targetServer;


  final EmbyRawItem? preloadedItem;


  final String? directStreamUrl;


  final Map<String, String> directStreamHeaders;

  const PlaybackRequest({
    required this.itemId,
    this.mediaSourceId,
    this.startPositionTicks,
    this.preferredSubtitleStreamIndex,
    this.preferredAudioStreamIndex,
    required this.subtitleSettings,
    required this.playerSettings,
    required this.danmakuSettings,
    this.audioSettings = const AudioSettingsState(),
    this.playFromStart = false,
    this.targetServer,
    this.preloadedItem,
    this.directStreamUrl,
    this.directStreamHeaders = const <String, String>{},
  });


  factory PlaybackRequest.fromEpisode({
    required EmbyRawItem episode,
    required SubtitleStyleSettings subtitleSettings,
    required PlayerSettingsState playerSettings,
    required DanmakuSettingsState danmakuSettings,
    AudioSettingsState audioSettings = const AudioSettingsState(),
  }) {
    return PlaybackRequest(
      itemId: episode.Id,
      startPositionTicks: episode.UserData?.PlaybackPositionTicks,
      subtitleSettings: subtitleSettings,
      playerSettings: playerSettings,
      danmakuSettings: danmakuSettings,
      audioSettings: audioSettings,
      preloadedItem: episode,
    );
  }

  PlaybackRequest copyWith({
    String? itemId,
    String? mediaSourceId,
    int? startPositionTicks,
    int? preferredSubtitleStreamIndex,
    int? preferredAudioStreamIndex,
    SubtitleStyleSettings? subtitleSettings,
    PlayerSettingsState? playerSettings,
    DanmakuSettingsState? danmakuSettings,
    AudioSettingsState? audioSettings,
    bool? playFromStart,
    PlaybackServerIdentity? targetServer,
    Object? preloadedItem = _noChange,
  }) {
    return PlaybackRequest(
      itemId: itemId ?? this.itemId,
      mediaSourceId: mediaSourceId ?? this.mediaSourceId,
      startPositionTicks: startPositionTicks ?? this.startPositionTicks,
      preferredSubtitleStreamIndex:
          preferredSubtitleStreamIndex ?? this.preferredSubtitleStreamIndex,
      preferredAudioStreamIndex:
          preferredAudioStreamIndex ?? this.preferredAudioStreamIndex,
      subtitleSettings: subtitleSettings ?? this.subtitleSettings,
      playerSettings: playerSettings ?? this.playerSettings,
      danmakuSettings: danmakuSettings ?? this.danmakuSettings,
      audioSettings: audioSettings ?? this.audioSettings,
      playFromStart: playFromStart ?? this.playFromStart,
      targetServer: targetServer ?? this.targetServer,
      preloadedItem: identical(preloadedItem, _noChange)
          ? this.preloadedItem
          : preloadedItem as EmbyRawItem?,
      directStreamUrl: directStreamUrl,
      directStreamHeaders: directStreamHeaders,
    );
  }
}

const Object _noChange = Object();


class PlaybackContext {
  final String itemId;
  final String itemName;
  final String? itemType;
  final int? itemIndexNumber;
  final String? seriesName;
  final String? seriesId;
  final String? seasonId;
  final String? mediaSourceId;
  final String? playSessionId;
  final int? runTimeTicks;
  final String playMethod;


  final bool isDolbyVision;

  final List<EmbySubtitleTrack> embySubtitles;
  final List<EmbyAudioTrack> embyAudioTracks;
  final List<EmbyRawMediaSource> allMediaSources;


  final Map<String, String> providerIds;


  final Map<String, String> seriesProviderIds;

  final int? parentIndexNumber;


  final DanmakuMatchContext danmakuMatchContext;


  final String serverId;
  final String userId;


  final String baseUrl;
  final String token;

  final String? logoUrl;

  const PlaybackContext({
    required this.itemId,
    required this.itemName,
    required this.itemType,
    required this.itemIndexNumber,
    required this.seriesName,
    required this.seriesId,
    required this.seasonId,
    required this.mediaSourceId,
    required this.playSessionId,
    required this.runTimeTicks,
    required this.playMethod,
    this.isDolbyVision = false,
    required this.danmakuMatchContext,
    required this.serverId,
    required this.userId,
    required this.baseUrl,
    required this.token,
    this.embySubtitles = const [],
    this.embyAudioTracks = const [],
    this.allMediaSources = const [],
    this.providerIds = const {},
    this.seriesProviderIds = const {},
    this.parentIndexNumber,
    this.logoUrl,
  });


  String get memoryKey => playbackMemoryKey(
    serverId: serverId,
    userId: userId,
    itemId: itemId,
    seriesId: seriesId,
  );
}
