import 'dart:async';

import 'package:chewie/chewie.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/asset_viewer/providers/show_controls.provider.dart';
import 'package:immich_mobile/modules/asset_viewer/providers/video_player_controls_provider.dart';
import 'package:immich_mobile/modules/asset_viewer/providers/video_player_value_provider.dart';
import 'package:immich_mobile/modules/asset_viewer/ui/center_play_button.dart';
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
import 'package:video_player/video_player.dart';

class VideoPlayerControls extends ConsumerStatefulWidget {
  const VideoPlayerControls({
    Key? key,
  }) : super(key: key);

  @override
  VideoPlayerControlsState createState() => VideoPlayerControlsState();
}

class VideoPlayerControlsState extends ConsumerState<VideoPlayerControls>
    with SingleTickerProviderStateMixin {
  late VideoPlayerController controller;
  late VideoPlayerValue _latestValue;
  bool _displayBufferingIndicator = false;
  double? _latestVolume;
  Timer? _hideTimer;

  ChewieController? _chewieController;
  ChewieController get chewieController => _chewieController!;

  @override
  Widget build(BuildContext context) {
    ref.listen(videoPlayerControlsProvider.select((value) => value.mute),
        (_, value) {
      _mute(value);
      _cancelAndRestartTimer();
    });

    ref.listen(videoPlayerControlsProvider.select((value) => value.position),
        (_, position) {
      _seekTo(position);
      _cancelAndRestartTimer();
    });

    if (_latestValue.hasError) {
      return chewieController.errorBuilder?.call(
            context,
            chewieController.videoPlayerController.value.errorDescription!,
          ) ??
          const Center(
            child: Icon(
              Icons.error,
              color: Colors.white,
              size: 42,
            ),
          );
    }

    return GestureDetector(
      onTap: () => _cancelAndRestartTimer(),
      child: AbsorbPointer(
        absorbing: !ref.watch(showControlsProvider),
        child: Stack(
          children: [
            if (_displayBufferingIndicator)
              const Center(
                child: ImmichLoadingIndicator(),
              )
            else
              _buildHitArea(),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _dispose();
    super.dispose();
  }

  void _dispose() {
    controller.removeListener(_updateState);
    _hideTimer?.cancel();
  }

  @override
  void didChangeDependencies() {
    final oldController = _chewieController;
    _chewieController = ChewieController.of(context);
    controller = chewieController.videoPlayerController;

    if (oldController != chewieController) {
      _dispose();
      _initialize();
    }

    super.didChangeDependencies();
  }

  Widget _buildHitArea() {
    final bool isFinished = _latestValue.position >= _latestValue.duration;

    return GestureDetector(
      onTap: () {
        if (_latestValue.isPlaying) {
          ref.read(showControlsProvider.notifier).show = false;
        } else {
          _playPause();
          ref.read(showControlsProvider.notifier).show = false;
        }
      },
      child: CenterPlayButton(
        backgroundColor: Colors.black54,
        iconColor: Colors.white,
        isFinished: isFinished,
        isPlaying: controller.value.isPlaying,
        show: ref.watch(showControlsProvider),
        onPressed: _playPause,
      ),
    );
  }

  void _cancelAndRestartTimer() {
    _hideTimer?.cancel();
    _startHideTimer();
    ref.read(showControlsProvider.notifier).show = true;
  }

  Future<void> _initialize() async {
    _mute(ref.read(videoPlayerControlsProvider.select((value) => value.mute)));

    controller.addListener(_updateState);
    _latestValue = controller.value;

    if (controller.value.isPlaying || chewieController.autoPlay) {
      _startHideTimer();
    }
  }

  void _playPause() {
    final isFinished = _latestValue.position >= _latestValue.duration;

    setState(() {
      if (controller.value.isPlaying) {
        ref.read(showControlsProvider.notifier).show = true;
        _hideTimer?.cancel();
        controller.pause();
      } else {
        _cancelAndRestartTimer();

        if (!controller.value.isInitialized) {
          controller.initialize().then((_) {
            controller.play();
          });
        } else {
          if (isFinished) {
            controller.seekTo(Duration.zero);
          }
          controller.play();
        }
      }
    });
  }

  void _startHideTimer() {
    final hideControlsTimer = chewieController.hideControlsTimer.isNegative
        ? ChewieController.defaultHideControlsTimer
        : chewieController.hideControlsTimer;
    _hideTimer = Timer(hideControlsTimer, () {
      ref.read(showControlsProvider.notifier).show = false;
    });
  }

  void _updateState() {
    if (!mounted) return;

    _displayBufferingIndicator = controller.value.isBuffering;

    setState(() {
      _latestValue = controller.value;
      ref.read(videoPlaybackValueProvider.notifier).value = VideoPlaybackValue(
        position: _latestValue.position,
        duration: _latestValue.duration,
      );
    });
  }

  void _mute(bool mute) {
    if (mute) {
      _latestVolume = controller.value.volume;
      controller.setVolume(0);
    } else {
      controller.setVolume(_latestVolume ?? 0.5);
    }
  }

  void _seekTo(double position) {
    final Duration pos = controller.value.duration * (position / 100.0);
    if (pos != controller.value.position) {
      controller.seekTo(pos);
    }
  }
}
