/*
 * Copyright © 2020, Simform Solutions
 * All rights reserved.
 * https://github.com/simformsolutions/flutter_showcaseview
 */

/*
Customized By: Ibrahim Albitar

*/

import 'package:doctor_app_flutter/widgets/shared/app_texts_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

import 'app_anchored_overlay_widget.dart';
import 'app_get_position.dart';
import 'app_shape_painter.dart';
import 'app_showcase_widget.dart';
import 'app_tool_tip_widget.dart';

class AppShowcase extends StatefulWidget {
  final Widget child;
  final String title;
  final String description;
  final ShapeBorder shapeBorder;
  final TextStyle titleTextStyle;
  final TextStyle descTextStyle;
  final GlobalKey key;
  final Color overlayColor;
  final double overlayOpacity;
  final Widget container;
  final Color showcaseBackgroundColor;
  final Color textColor;
  final bool showArrow;
  final double height;
  final double width;
  final Duration animationDuration;
  final VoidCallback onToolTipClick;
  final VoidCallback onTargetClick;
  final VoidCallback onSkipClick;
  final bool disposeOnTap;
  final bool disableAnimation;

  const AppShowcase(
      {@required this.key,
      @required this.child,
      this.title,
      @required this.description,
      this.shapeBorder,
      this.overlayColor = Colors.black,
      this.overlayOpacity = 0.75,
      this.titleTextStyle,
      this.descTextStyle,
      this.showcaseBackgroundColor = Colors.white,
      this.textColor = Colors.black,
      this.showArrow = true,
      this.onTargetClick,
      this.onSkipClick,
      this.disposeOnTap,
      this.animationDuration = const Duration(milliseconds: 2000),
      this.disableAnimation = false})
      : height = null,
        width = null,
        container = null,
        this.onToolTipClick = null,
        assert(overlayOpacity >= 0.0 && overlayOpacity <= 1.0,
            "overlay opacity should be >= 0.0 and <= 1.0."),
        assert(
            onTargetClick == null
                ? true
                : (disposeOnTap == null ? false : true),
            "disposeOnTap is required if you're using onTargetClick"),
        assert(
            disposeOnTap == null
                ? true
                : (onTargetClick == null ? false : true),
            "onTargetClick is required if you're using disposeOnTap"),
        assert(key != null ||
            child != null ||
            title != null ||
            showArrow != null ||
            description != null ||
            shapeBorder != null ||
            overlayColor != null ||
            titleTextStyle != null ||
            descTextStyle != null ||
            showcaseBackgroundColor != null ||
            textColor != null ||
            shapeBorder != null ||
            animationDuration != null);

  const AppShowcase.withWidget(
      {this.key,
      @required this.child,
      @required this.container,
      @required this.height,
      @required this.width,
      this.title,
      this.description,
      this.shapeBorder,
      this.overlayColor = Colors.black,
      this.overlayOpacity = 0.75,
      this.titleTextStyle,
      this.descTextStyle,
      this.showcaseBackgroundColor = Colors.white,
      this.textColor = Colors.black,
      this.onTargetClick,
      this.onSkipClick,
      this.disposeOnTap,
      this.animationDuration = const Duration(milliseconds: 2000),
      this.disableAnimation = false})
      : this.showArrow = false,
        this.onToolTipClick = null,
        assert(overlayOpacity >= 0.0 && overlayOpacity <= 1.0,
            "overlay opacity should be >= 0.0 and <= 1.0."),
        assert(key != null ||
            child != null ||
            title != null ||
            description != null ||
            shapeBorder != null ||
            overlayColor != null ||
            titleTextStyle != null ||
            descTextStyle != null ||
            showcaseBackgroundColor != null ||
            textColor != null ||
            shapeBorder != null ||
            animationDuration != null);

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

class _AppShowcaseState extends State<AppShowcase>
    with TickerProviderStateMixin {
  bool _showShowCase = false;
  Animation<double> _slideAnimation;
  AnimationController _slideAnimationController;

  GetPosition position;

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

    _slideAnimationController = AnimationController(
      duration: widget.animationDuration,
      vsync: this,
    )..addStatusListener((AnimationStatus status) {
        if (status == AnimationStatus.completed) {
          _slideAnimationController.reverse();
        }
        if (_slideAnimationController.isDismissed) {
          if (!widget.disableAnimation) {
            _slideAnimationController.forward();
          }
        }
      });

    _slideAnimation = CurvedAnimation(
      parent: _slideAnimationController,
      curve: Curves.easeInOut,
    );

    position = GetPosition(key: widget.key);
  }

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

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    showOverlay();
  }

  ///
  /// show overlay if there is any target widget
  ///
  void showOverlay() {
    GlobalKey activeStep = ShowCaseWidget.activeTargetWidget(context);
    setState(() {
      _showShowCase = activeStep == widget.key;
    });

    if (activeStep == widget.key) {
      if (!widget.disableAnimation) {
        _slideAnimationController.forward();
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return AnchoredOverlay(
      overlayBuilder: (BuildContext context, Rect rectBound, Offset offset) =>
          buildOverlayOnTarget(offset, rectBound.size, rectBound, size),
      showOverlay: true,
      child: widget.child,
    );
  }

  _nextIfAny() {
    ShowCaseWidget.of(context).completed(widget.key);
    if (!widget.disableAnimation) {
      _slideAnimationController.forward();
    }
  }

  _getOnTargetTap() {
    if (widget.disposeOnTap == true) {
      return widget.onTargetClick == null
          ? () {
              ShowCaseWidget.of(context).dismiss();
            }
          : () {
              ShowCaseWidget.of(context).dismiss();
              widget.onTargetClick();
            };
    } else {
      return widget.onTargetClick ?? _nextIfAny;
    }
  }

  _getOnTooltipTap() {
    if (widget.disposeOnTap == true) {
      return widget.onToolTipClick == null
          ? () {
              ShowCaseWidget.of(context).dismiss();
            }
          : () {
              ShowCaseWidget.of(context).dismiss();
              widget.onToolTipClick();
            };
    } else {
      return widget.onToolTipClick ?? () {};
    }
  }

  buildOverlayOnTarget(
    Offset offset,
    Size size,
    Rect rectBound,
    Size screenSize,
  ) =>
      Visibility(
        visible: _showShowCase,
        maintainAnimation: true,
        maintainState: true,
        child: Stack(
          children: [
            GestureDetector(
              onTap: _nextIfAny,
              child: Container(
                width: MediaQuery.of(context).size.width,
                height: MediaQuery.of(context).size.height,
                child: CustomPaint(
                  painter: ShapePainter(
                      opacity: widget.overlayOpacity,
                      rect: position.getRect(),
                      shapeBorder: widget.shapeBorder,
                      color: widget.overlayColor),
                ),
              ),
            ),
            _TargetWidget(
              offset: offset,
              size: size,
              onTap: _getOnTargetTap(),
              shapeBorder: widget.shapeBorder,
            ),
            AppToolTipWidget(
              position: position,
              offset: offset,
              screenSize: screenSize,
              title: widget.title,
              description: widget.description,
              animationOffset: _slideAnimation,
              titleTextStyle: widget.titleTextStyle,
              descTextStyle: widget.descTextStyle,
              container: widget.container,
              tooltipColor: widget.showcaseBackgroundColor,
              textColor: widget.textColor,
              showArrow: widget.showArrow,
              contentHeight: widget.height,
              contentWidth: widget.width,
              onTooltipTap: _getOnTooltipTap(),
            ),
            GestureDetector(
                child: AppText(
                  "Skip",
                  color: Colors.white,
                  fontSize: 20,
                  marginRight: 15,
                  marginLeft: 15,
                  marginTop: 15,
                ),
                onTap: widget.onSkipClick)
          ],
        ),
      );
}

class _TargetWidget extends StatelessWidget {
  final Offset offset;
  final Size size;
  final Animation<double> widthAnimation;
  final VoidCallback onTap;
  final ShapeBorder shapeBorder;

  _TargetWidget({
    Key key,
    @required this.offset,
    this.size,
    this.widthAnimation,
    this.onTap,
    this.shapeBorder,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Positioned(
      top: offset.dy,
      left: offset.dx,
      child: FractionalTranslation(
        translation: const Offset(-0.5, -0.5),
        child: GestureDetector(
          onTap: onTap,
          child: Container(
            height: size.height + 16,
            width: size.width + 16,
            decoration: ShapeDecoration(
              shape: shapeBorder ??
                  RoundedRectangleBorder(
                    borderRadius: const BorderRadius.all(
                      Radius.circular(8),
                    ),
                  ),
            ),
          ),
        ),
      ),
    );
  }
}
