// 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:math';

import 'package:dual_screen/dual_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/gallery_localizations.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({
    super.key,
    required this.isFinished,
    required super.child,
  });

  final bool isFinished;

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

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

class SplashPage extends StatefulWidget {
  const SplashPage({
    super.key,
    required this.child,
  });

  final Widget child;

  @override
  State<SplashPage> createState() => _SplashPageState();
}

class _SplashPageState extends State<SplashPage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late 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: const Duration(
          milliseconds: splashPageAnimationDurationInMilliseconds,
        ),
        vsync: this)
      ..addListener(() {
        setState(() {});
      });
  }

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

  Animation<RelativeRect> _getPanelAnimation(
    BuildContext context,
    BoxConstraints constraints,
  ) {
    final 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 = _getPanelAnimation(context, constraints);
            var frontLayer = widget.child;
            if (_isSplashVisible) {
              frontLayer = MouseRegion(
                cursor: SystemMouseCursors.click,
                child: 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: const BorderRadius.vertical(
                    top: Radius.circular(40),
                  ),
                  child: frontLayer,
                ),
              );
            }

            if (isDisplayFoldable(context)) {
              return TwoPane(
                startPane: frontLayer,
                endPane: GestureDetector(
                  onTap: () {
                    if (_isSplashVisible) {
                      _controller.reverse();
                    } else {
                      _controller.forward();
                    }
                  },
                  child: _SplashBackLayer(
                      isSplashCollapsed: !_isSplashVisible, effect: _effect),
                ),
              );
            } else {
              return Stack(
                children: [
                  _SplashBackLayer(
                    isSplashCollapsed: !_isSplashVisible,
                    effect: _effect,
                    onTap: () {
                      _controller.forward();
                    },
                  ),
                  PositionedTransition(
                    rect: animation,
                    child: frontLayer,
                  ),
                ],
              );
            }
          },
        ),
      ),
    );
  }
}

class _SplashBackLayer extends StatelessWidget {
  const _SplashBackLayer({
    required this.isSplashCollapsed,
    required this.effect,
    this.onTap,
  });

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

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

    Widget? child;
    if (isSplashCollapsed) {
      if (isDisplayDesktop(context)) {
        child = Padding(
          padding: const EdgeInsets.only(top: 50),
          child: Align(
            alignment: Alignment.topCenter,
            child: MouseRegion(
              cursor: SystemMouseCursors.click,
              child: GestureDetector(
                onTap: onTap,
                child: flutterLogo,
              ),
            ),
          ),
        );
      }
      if (isDisplayFoldable(context)) {
        child = Container(
          color: Theme.of(context).colorScheme.background,
          child: Stack(
            children: [
              Center(
                child: flutterLogo,
              ),
              Padding(
                padding: const EdgeInsets.only(top: 100.0),
                child: Center(
                  child: Text(
                    GalleryLocalizations.of(context)!.splashSelectDemo,
                  ),
                ),
              )
            ],
          ),
        );
      }
    } else {
      child = Stack(
        children: [
          Center(
            child: Image.asset(
              effectAsset,
              package: 'flutter_gallery_assets',
            ),
          ),
          Center(child: flutterLogo),
        ],
      );
    }

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