import 'package:freezed_annotation/freezed_annotation.dart';

import 'library.dart';

part 'playback.freezed.dart';
part 'playback.g.dart';

@freezed
abstract class PlaybackRequestPayload with _$PlaybackRequestPayload {
  const factory PlaybackRequestPayload({
    required String itemId,
    @JsonKey(includeIfNull: false) String? itemType,
    @JsonKey(includeIfNull: false) String? mediaSourceId,
    @JsonKey(includeIfNull: false) int? startPositionTicks,
    @Default(false) bool playFromStart,
  }) = _PlaybackRequestPayload;

  factory PlaybackRequestPayload.fromJson(Map<String, dynamic> json) =>
      _$PlaybackRequestPayloadFromJson(json);
}


@freezed
abstract class EmbySubtitleTrack with _$EmbySubtitleTrack {
  const factory EmbySubtitleTrack({
    @JsonKey(fromJson: _intRequired) required int index,
    @JsonKey(includeIfNull: false) String? title,
    @JsonKey(includeIfNull: false) String? language,
    @JsonKey(fromJson: _boolOrFalse) @Default(false) bool isDefault,
    @JsonKey(fromJson: _boolOrFalse) @Default(false) bool isForced,
    @JsonKey(fromJson: _boolOrFalse) @Default(false) bool isExternal,
    @JsonKey(includeIfNull: false) String? deliveryUrl,
    @JsonKey(includeIfNull: false) String? codec,
  }) = _EmbySubtitleTrack;

  factory EmbySubtitleTrack.fromJson(Map<String, dynamic> json) =>
      _$EmbySubtitleTrackFromJson(json);
}


@freezed
abstract class EmbyAudioTrack with _$EmbyAudioTrack {
  const factory EmbyAudioTrack({
    @JsonKey(fromJson: _intRequired) required int index,
    @JsonKey(includeIfNull: false) String? title,
    @JsonKey(includeIfNull: false) String? language,
    @JsonKey(includeIfNull: false) String? codec,
    @JsonKey(fromJson: _intOrNull, includeIfNull: false) int? channels,
    @JsonKey(includeIfNull: false) String? displayTitle,
    @JsonKey(fromJson: _boolOrFalse) @Default(false) bool isDefault,
  }) = _EmbyAudioTrack;

  factory EmbyAudioTrack.fromJson(Map<String, dynamic> json) =>
      _$EmbyAudioTrackFromJson(json);
}

int _intRequired(Object? value) => (value as num).toInt();

int? _intOrNull(Object? value) => (value as num?)?.toInt();

bool _boolOrFalse(Object? value) => (value as bool?) ?? false;


class PlaybackRequestResult {

  final String streamUrl;


  final String? container;


  final String? mimeType;


  final bool directStream;


  final EmbyRawItem item;


  final EmbyRawMediaSource? mediaSource;


  final double startPositionSeconds;


  final double? durationSeconds;


  final List<EmbySubtitleTrack> subtitles;


  final int? defaultSubtitleIndex;


  final List<EmbyAudioTrack> audioTracks;


  final int? defaultAudioStreamIndex;


  final String? playSessionId;


  final String playMethod;

  const PlaybackRequestResult({
    required this.streamUrl,
    this.container,
    this.mimeType,
    required this.directStream,
    required this.item,
    this.mediaSource,
    this.startPositionSeconds = 0,
    this.durationSeconds,
    this.subtitles = const [],
    this.defaultSubtitleIndex,
    this.audioTracks = const [],
    this.defaultAudioStreamIndex,
    this.playSessionId,
    this.playMethod = 'DirectStream',
  });
}


class PlaybackReportPayload {
  final String itemId;
  final String? mediaSourceId;
  final String? playSessionId;
  final int positionTicks;
  final int? runTimeTicks;
  final String playMethod;
  final bool canSeek;
  final bool isPaused;
  final bool isMuted;
  final double playbackRate;
  final int playlistIndex;
  final int playlistLength;
  final String repeatMode;
  final String? eventName;

  const PlaybackReportPayload({
    required this.itemId,
    this.mediaSourceId,
    this.playSessionId,
    required this.positionTicks,
    this.runTimeTicks,
    this.playMethod = 'DirectStream',
    this.canSeek = true,
    this.isPaused = false,
    this.isMuted = false,
    this.playbackRate = 1,
    this.playlistIndex = 0,
    this.playlistLength = 1,
    this.repeatMode = 'RepeatNone',
    this.eventName,
  });

  Map<String, dynamic> toJson({bool includeNowPlayingQueue = false}) => {
    'ItemId': itemId,
    if (mediaSourceId != null && mediaSourceId!.isNotEmpty)
      'MediaSourceId': mediaSourceId,
    if (playSessionId != null && playSessionId!.isNotEmpty)
      'PlaySessionId': playSessionId,
    'PositionTicks': positionTicks,
    if (runTimeTicks != null) 'RunTimeTicks': runTimeTicks,
    'CanSeek': canSeek,
    'PlayMethod': playMethod,
    'PlaylistIndex': playlistIndex,
    'PlaylistLength': playlistLength,
    'PlaybackRate': playbackRate,
    'IsMuted': isMuted,
    'IsPaused': isPaused,
    'RepeatMode': repeatMode,
    if (eventName != null && eventName!.isNotEmpty) 'EventName': eventName,
    if (includeNowPlayingQueue)
      'NowPlayingQueue': [
        {'Id': itemId, 'PlaylistItemId': 'playlistItem$playlistIndex'},
      ],
  };
}
