// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:gallery/constants.dart';
import 'package:gallery/layout/adaptive.dart';
import 'package:gallery/pages/home.dart';

const homePeekDesktop = 210.0;
const homePeekMobile = 60.0;

class SplashPageAnimation extends InheritedWidget {
  const SplashPageAnimation({
    Key key,
    @required this.isFinished,
    @required Widget child,
  })  : assert(child != null),
        super(key: key, child: child);

  final bool isFinished;

  static SplashPageAnimation of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType();
  }

  @override
  bool updateShouldNotify(SplashPageAnimation old) => true;
}

class SplashPage extends StatefulWidget {
  const SplashPage({
    Key key,
    this.isAnimated = true,
    @required this.child,
  }) : super(key: key);

  final bool isAnimated;
  final Widget child;

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

class _SplashPageState extends State<SplashPage>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Timer _launchTimer;
  int _effect;
  final _random = Random();

  // A map of the effect index to its duration. This duration is used to
  // determine how long to display the splash animation at launch.
  //
  // If a new effect is added, this map should be updated.
  final _effectDurations = {
    1: 5,
    2: 4,
    3: 4,
    4: 5,
    5: 5,
    6: 4,
    7: 4,
    8: 4,
    9: 3,
    10: 6,
  };

  bool get _isSplashVisible {
    return _controller.status == AnimationStatus.completed ||
        _controller.status == AnimationStatus.forward;
  }

  @override
  void initState() {
    super.initState();

    // If the number of included effects changes, this number should be changed.
    _effect = _random.nextInt(_effectDurations.length) + 1;

    _controller = AnimationController(
        duration: Duration(
          milliseconds: splashPageAnimationDurationInMilliseconds,
        ),
        value: 1,
        vsync: this)
      ..addListener(() {
        this.setState(() {});
      });
    if (widget.isAnimated) {
      _launchTimer = Timer(
        Duration(seconds: _effectDurations[_effect]),
        () {
          _controller.fling(velocity: -1);
        },
      );
    } else {
      _controller.value = 0;
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    _launchTimer?.cancel();
    _launchTimer = null;
    super.dispose();
  }

  Animation<RelativeRect> _getPanelAnimation(
    BuildContext context,
    BoxConstraints constraints,
  ) {
    final double height = constraints.biggest.height -
        (isDisplayDesktop(context) ? homePeekDesktop : homePeekMobile);
    return RelativeRectTween(
      begin: const RelativeRect.fromLTRB(0, 0, 0, 0),
      end: RelativeRect.fromLTRB(0, height, 0, 0),
    ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut));
  }

  @override
  Widget build(BuildContext context) {
    return NotificationListener<ToggleSplashNotification>(
      onNotification: (_) {
        _controller.forward();
        return true;
      },
      child: SplashPageAnimation(
        isFinished: _controller.status == AnimationStatus.dismissed,
        child: LayoutBuilder(
          builder: (context, constraints) {
            final Animation<RelativeRect> animation =
                _getPanelAnimation(context, constraints);
            Widget frontLayer = widget.child;
            if (_isSplashVisible) {
              frontLayer = GestureDetector(
                behavior: HitTestBehavior.opaque,
                onTap: () {
                  _controller.reverse();
                },
                onVerticalDragEnd: (details) {
                  if (details.velocity.pixelsPerSecond.dy < -200) {
                    _controller.reverse();
                  }
                },
                child: IgnorePointer(child: frontLayer),
              );
            }

            if (isDisplayDesktop(context)) {
              frontLayer = Padding(
                padding: const EdgeInsets.only(top: 136),
                child: ClipRRect(
                  borderRadius: BorderRadius.vertical(
                    top: Radius.circular(40),
                  ),
                  child: frontLayer,
                ),
              );
            }

            return Stack(
              children: [
                _SplashBackLayer(
                  isSplashCollapsed: !_isSplashVisible,
                  effect: _effect,
                  onTap: () {
                    _controller.forward();
                  },
                ),
                PositionedTransition(
                  rect: animation,
                  child: frontLayer,
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}

class _SplashBackLayer extends StatelessWidget {
  _SplashBackLayer({
    Key key,
    @required this.isSplashCollapsed,
    this.effect,
    this.onTap,
  }) : super(key: key);

  final bool isSplashCollapsed;
  final int effect;
  final GestureTapCallback onTap;

  @override
  Widget build(BuildContext context) {
    var effectAsset = 'assets/splash_effects/splash_effect_$effect.gif';
    final flutterLogo = Image.asset('assets/logo/flutter_logo.png');

    Widget child;
    if (isSplashCollapsed) {
      child = isDisplayDesktop(context)
          ? Padding(
              padding: const EdgeInsets.only(top: 50),
              child: Align(
                alignment: Alignment.topCenter,
                child: GestureDetector(
                  onTap: onTap,
                  child: flutterLogo,
                ),
              ),
            )
          : null;
    } else {
      child = Stack(
        children: [
          Center(child: Image.asset(effectAsset)),
          Center(child: flutterLogo),
        ],
      );
    }

    return ExcludeSemantics(
      child: Container(
        color: Color(0xFF030303), // This is the background color of the gifs.
        padding: EdgeInsets.only(
          bottom: isDisplayDesktop(context) ? homePeekDesktop : homePeekMobile,
        ),
        child: child,
      ),
    );
  }
}
