import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/api/api.dart';
import 'package:nc_photos/api/api_util.dart' as api_util;
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/platform/k.dart' as platform_k;
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/request_public_link.dart';
import 'package:nc_photos/widget/animated_visibility.dart';
import 'package:video_player/video_player.dart';
import 'package:wakelock/wakelock.dart';

class VideoViewer extends StatefulWidget {
  VideoViewer({
    required this.account,
    required this.file,
    this.onLoaded,
    this.onHeightChanged,
    this.onPlay,
    this.onPause,
    this.isControlVisible = false,
    this.canPlay = true,
  });

  @override
  createState() => _VideoViewerState();

  final Account account;
  final File file;
  final VoidCallback? onLoaded;
  final ValueChanged<double>? onHeightChanged;
  final VoidCallback? onPlay;
  final VoidCallback? onPause;
  final bool isControlVisible;
  final bool canPlay;
}

class _VideoViewerState extends State<VideoViewer> {
  @override
  initState() {
    super.initState();
    _getVideoUrl().then((url) {
      setState(() {
        _initController(url);
      });
    }).onError((e, stacktrace) {
      _log.shout("[initState] Failed while _getVideoUrl", e, stacktrace);
      SnackBarManager().showSnackBar(SnackBar(
        content: Text(exception_util.toUserString(e)),
        duration: k.snackBarDurationNormal,
      ));
    });

    Wakelock.enable();
  }

  @override
  build(BuildContext context) {
    Widget content;
    if (_isControllerInitialized && _controller.value.isInitialized) {
      content = _buildPlayer(context);
    } else {
      content = Container();
    }

    return Container(
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.height,
      alignment: Alignment.center,
      child: content,
    );
  }

  @override
  dispose() {
    super.dispose();
    _controller.dispose();
    Wakelock.disable();
  }

  void _initController(String url) async {
    try {
      _controller = VideoPlayerController.network(
        url,
        httpHeaders: {
          "Authorization": Api.getAuthorizationHeaderValue(widget.account),
        },
      );
      await _controller.initialize();
      widget.onLoaded?.call();
      WidgetsBinding.instance!.addPostFrameCallback((_) {
        if (_key.currentContext != null) {
          widget.onHeightChanged?.call(_key.currentContext!.size!.height);
        }
      });
      _controller.addListener(_onControllerChanged);
      _isControllerInitialized = true;
      setState(() {
        _play();
      });
    } catch (e, stackTrace) {
      _log.shout("[_initController] Failed while initialize", e, stackTrace);
      SnackBarManager().showSnackBar(SnackBar(
        content: Text(exception_util.toUserString(e)),
        duration: k.snackBarDurationNormal,
      ));
    }
  }

  Widget _buildPlayer(BuildContext context) {
    if (_controller.value.isPlaying && !widget.canPlay) {
      WidgetsBinding.instance!.addPostFrameCallback((_) {
        _pause();
      });
    }

    return Stack(
      children: [
        Align(
          alignment: Alignment.center,
          child: AspectRatio(
            key: _key,
            aspectRatio: _controller.value.aspectRatio,
            child: IgnorePointer(
              child: VideoPlayer(_controller),
            ),
          ),
        ),
        Positioned.fill(
          child: AnimatedVisibility(
            opacity: widget.isControlVisible ? 1.0 : 0.0,
            duration: k.animationDurationNormal,
            child: Container(
              color: Colors.black45,
              child: Center(
                child: IconButton(
                  icon: Icon(_controller.value.isPlaying
                      ? Icons.pause_circle_filled
                      : Icons.play_circle_filled),
                  iconSize: 48,
                  padding: const EdgeInsets.all(16),
                  color: Colors.white,
                  onPressed: () => _controller.value.isPlaying
                      ? _onPausePressed()
                      : _onPlayPressed(),
                ),
              ),
            ),
          ),
        ),
        Container(
          child: Align(
            alignment: Alignment.bottomCenter,
            child: Padding(
              padding: EdgeInsets.only(
                  bottom: kToolbarHeight + 8, left: 8, right: 8),
              child: AnimatedVisibility(
                opacity: widget.isControlVisible ? 1.0 : 0.0,
                duration: k.animationDurationNormal,
                child: Material(
                  type: MaterialType.transparency,
                  child: Row(
                    children: [
                      ValueListenableBuilder(
                        valueListenable: _controller,
                        builder: (context, VideoPlayerValue value, child) =>
                            Text(
                          _durationToString(value.position),
                          style: TextStyle(
                            fontSize: 14,
                            color: AppTheme.getSecondaryTextColor(context),
                          ),
                        ),
                      ),
                      const SizedBox(width: 8),
                      Expanded(
                        child: VideoProgressIndicator(
                          _controller,
                          allowScrubbing: true,
                          padding: const EdgeInsets.symmetric(vertical: 8),
                          colors: VideoProgressColors(
                            backgroundColor: Colors.white24,
                            bufferedColor: Colors.white38,
                            playedColor: Colors.white,
                          ),
                        ),
                      ),
                      const SizedBox(width: 8),
                      if (_controller.value.duration != Duration.zero)
                        Text(
                          _durationToString(_controller.value.duration),
                          style: TextStyle(
                            fontSize: 14,
                            color: AppTheme.getSecondaryTextColor(context),
                          ),
                        ),
                      const SizedBox(width: 4),
                      InkWell(
                        borderRadius: BorderRadius.all(Radius.circular(32)),
                        onTap: _onVolumnPressed,
                        child: Padding(
                          padding: const EdgeInsets.all(4),
                          child: Icon(
                            _controller.value.volume == 0
                                ? Icons.volume_mute_outlined
                                : Icons.volume_up_outlined,
                            color: AppTheme.getSecondaryTextColor(context),
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }

  void _onPlayPressed() {
    if (_controller.value.position == _controller.value.duration) {
      _controller.seekTo(const Duration()).then((_) {
        setState(() {
          _play();
        });
      });
    } else {
      setState(() {
        _play();
      });
    }
  }

  void _onPausePressed() {
    setState(() {
      _pause();
    });
  }

  void _onControllerChanged() {
    if (!_controller.value.isInitialized) {
      return;
    }
    if (!_isFinished &&
        _controller.value.position == _controller.value.duration) {
      _isFinished = true;
      setState(() {
        _pause();
      });
    }
  }

  void _onVolumnPressed() {
    setState(() {
      if (_controller.value.volume == 0) {
        _controller.setVolume(1);
      } else {
        _controller.setVolume(0);
      }
    });
  }

  void _play() {
    if (widget.canPlay) {
      _isFinished = false;
      _controller.play();
      widget.onPlay?.call();
    }
  }

  void _pause() {
    _controller.pause();
    widget.onPause?.call();
  }

  Future<String> _getVideoUrl() async {
    if (platform_k.isWeb) {
      return RequestPublicLink()(widget.account, widget.file);
    } else {
      return api_util.getFileUrl(widget.account, widget.file);
    }
  }

  final _key = GlobalKey();
  bool _isControllerInitialized = false;
  late VideoPlayerController _controller;
  var _isFinished = false;

  static final _log = Logger("widget.video_viewer._VideoViewerState");
}

String _durationToString(Duration duration) {
  String product = "";
  if (duration.inHours > 0) {
    product += "${duration.inHours}:";
  }
  final minStr = (duration.inMinutes % 60).toString().padLeft(2, "0");
  final secStr = (duration.inSeconds % 60).toString().padLeft(2, "0");
  product += "$minStr:$secStr";
  return product;
}