import 'dart:async';

import 'package:flutter/material.dart';

import 'package:fladder/models/items/media_streams_model.dart';
import 'package:fladder/models/playback/playback_model.dart';
import 'package:fladder/models/settings/video_player_settings.dart';
import 'package:fladder/src/video_player_helper.g.dart';
import 'package:fladder/wrappers/players/base_player.dart';
import 'package:fladder/wrappers/players/player_states.dart';

class NativePlayer extends BasePlayer implements VideoPlayerListenerCallback {
  final player = VideoPlayerApi();

  @override
  Future<void> dispose() async {
    return NativeVideoActivity().disposeActivity();
  }

  @override
  Future<void> init(VideoPlayerSettingsModel settings) async => VideoPlayerListenerCallback.setUp(this);

  @override
  Future<void> loop(bool loop) {
    return player.setLooping(loop);
  }

  @override
  Future<void> loadVideo(String url, bool play) async => player.open(url, play);

  @override
  Future<void> open(BuildContext newContext) async => NativeVideoActivity().launchActivity();

  @override
  Future<void> pause() {
    return player.pause();
  }

  @override
  Future<void> play() => player.play();

  @override
  Future<void> playOrPause() async {
    return;
  }

  @override
  Future<void> seek(Duration position) {
    return player.seekTo(position.inMilliseconds);
  }

  @override
  Future<int> setAudioTrack(AudioStreamModel? model, PlaybackModel playbackModel) async {
    return 0;
  }

  @override
  Future<void> setSpeed(double speed) async {}

  @override
  Future<int> setSubtitleTrack(SubStreamModel? model, PlaybackModel playbackModel) async {
    return 0;
  }

  @override
  Future<void> setVolume(double volume) async {
    return player.setVolume(volume);
  }

  @override
  Future<void> stop() async {
    return player.stop();
  }

  @override
  Widget? subtitles(bool showOverlay, {GlobalKey<State<StatefulWidget>>? controlsKey}) => null;

  @override
  Widget? videoWidget(Key key, BoxFit fit) => null;

  @override
  void onPlaybackStateChanged(PlaybackState state) {
    lastState = lastState.update(
      playing: state.playing,
      position: Duration(milliseconds: state.position),
      buffer: Duration(milliseconds: state.buffered),
      buffering: state.buffering,
    );
    _stateController.add(lastState);
  }

  final StreamController<PlayerState> _stateController = StreamController.broadcast();

  @override
  Stream<PlayerState> get stateStream => _stateController.stream;

  Future<void> sendPlaybackDataToNative(
    BuildContext? context,
    PlaybackModel model,
    Duration startPosition,
  ) async {
    final playableData = PlayableData(
      id: model.item.id,
      title: model.item.title,
      subTitle: context != null ? model.item.label(context) : "",
      logoUrl: model.item.getPosters?.logo?.path,
      startPosition: startPosition.inMilliseconds,
      description: model.item.overview.summary,
      defaultAudioTrack: model.mediaStreams?.defaultAudioStreamIndex ?? 1,
      nextVideo: model.nextVideo?.name,
      previousVideo: model.previousVideo?.name,
      audioTracks: model.audioStreams
              ?.map(
                (audio) => AudioTrack(
                  name: audio.displayTitle,
                  languageCode: audio.language,
                  codec: audio.codec,
                  index: audio.index,
                  external: false,
                ),
              )
              .toList() ??
          [],
      defaultSubtrack: model.mediaStreams?.defaultSubStreamIndex ?? 1,
      subtitleTracks: model.subStreams
              ?.map(
                (sub) => SubtitleTrack(
                  name: sub.displayTitle,
                  languageCode: sub.language,
                  codec: sub.codec,
                  index: sub.index,
                  external: sub.isExternal,
                  url: sub.url,
                ),
              )
              .toList() ??
          [],
      segments: model.mediaSegments?.segments
              .map(
                (e) => MediaSegment(
                  type: MediaSegmentType.values.firstWhere((element) => element.name == e.type.name),
                  name: context != null ? e.type.label(context) : e.type.name,
                  start: e.start.inMilliseconds,
                  end: e.end.inMilliseconds,
                ),
              )
              .toList() ??
          [],
      trickPlayModel: model.trickPlay != null
          ? TrickPlayModel(
              width: model.trickPlay!.width,
              height: model.trickPlay!.height,
              tileWidth: model.trickPlay!.tileWidth,
              tileHeight: model.trickPlay!.tileHeight,
              thumbnailCount: model.trickPlay!.thumbnailCount,
              interval: model.trickPlay!.interval.inMilliseconds,
              images: model.trickPlay?.images ?? [])
          : null,
      chapters: model.chapters
              ?.map((e) => Chapter(name: e.name, url: e.imageUrl, time: e.startPosition.inMilliseconds))
              .toList() ??
          [],
      url: model.media?.url ?? "",
    );
    player.sendPlayableModel(playableData);
  }
}
