import 'dart:collection';
import 'dart:ui';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/widgets/dialog_trial.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:aitrainer_app/widgets/menu_search_bar.dart';
import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:badges/badges.dart';
import 'package:ezanimation/ezanimation.dart';
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';

// ignore: must_be_immutable
class MenuPageWidget extends StatefulWidget {
  int? parent;

  MenuPageWidget({this.parent});

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

class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
  final double baseWidth = 312;
  final double baseHeight = 675.2;
  late MenuBloc menuBloc;
  //late TutorialBloc tutorialBloc;
  final scrollController = ScrollController();
  final bool activeExercisePlan = Cache().activeExercisePlan != null;
  final EzAnimation animation = EzAnimation(35.0, 10.0, Duration(seconds: 2), reverseCurve: Curves.linear);

  @override
  void initState() {
    if (activeExercisePlan || Cache().myTrainingPlan != null) {
      animation.start();
      animation.addStatusListener((status) {
        if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) {
          animation.reverse();
        }
      });
      animation.addListener(() {});
    }

    /// We require the initializers to run after the loading screen is rendered
    SchedulerBinding.instance!.addPostFrameCallback((_) {
      menuBloc.add(MenuCreate());
    });

    super.initState();
  }

  @override
  bool didUpdateWidget(MenuPageWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    scrollController.animateTo(5, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
    runDelayedEvent();
    return true;
  }

  Future runDelayedEvent() async {
    await Future.delayed(Duration(milliseconds: 500), () async {
      if (Cache().userLoggedIn != null) {
        await initDynamicLinks();
      }
      if (Cache().canTrial()) {
        showDialog(
            context: context,
            builder: (BuildContext context) {
              return DialogTrialWidget(
                title: t("10 days Premium for free"),
                description: t("Would you like to try all premium functions for 10 days, without any subscription or bank card data?"),
                widget: Column(children: [
                  Text(
                    t("If you click to 'Yes', all premium functions will be available right now."),
                    style: GoogleFonts.inter(color: Colors.white),
                  ),
                  Divider(),
                  Text(
                    t("If you click to 'No', you can use all basic functions, and you will loose the oppurtunity to try the premium functions for free."),
                    style: GoogleFonts.inter(color: Colors.white),
                  ),
                ]),
                onCancel: () => {
                  Navigator.of(context).pop(),
                  menuBloc.add(MenuStartTrial(start: DateTime.parse("1900-01-01 00:00:00"))),
                },
                onTap: () => {Navigator.of(context).pop(), menuBloc.add(MenuStartTrial(start: DateTime.now()))},
              );
            });
      }
    });
  }

  Future<void> initDynamicLinks() async {
    FirebaseDynamicLinks.instance.onLink(onSuccess: (PendingDynamicLinkData? dynamicLink) async {
      final Uri? deepLink = dynamicLink?.link;
      print("DeepLink: $deepLink");
      if (deepLink != null) {
        // ignore: unawaited_futures
        final String deepLinkPath = deepLink.path.replaceFirst("/", "");
        Navigator.pushNamed(context, deepLinkPath);
      }
    }, onError: (OnLinkErrorException e) async {
      print('onLinkError');
      print(e.message);
    });

    final PendingDynamicLinkData? data = await FirebaseDynamicLinks.instance.getInitialLink();
    final Uri? deepLink = data?.link;
    print("Pending DeepLink: $deepLink");
    if (deepLink != null) {
      // ignore: unawaited_futures
      final String deepLinkPath = deepLink.path.replaceFirst("/", "");
      Navigator.pushNamed(context, deepLinkPath);
    }
  }

  @override
  Widget build(BuildContext context) {
    menuBloc = BlocProvider.of<MenuBloc>(context);
    //tutorialBloc = BlocProvider.of<TutorialBloc>(context);
    setContext(context);
    double cWidth = MediaQuery.of(context).size.width;
    double cHeight = MediaQuery.of(context).size.height;

    if (widget.parent == null) {
      widget.parent = 0;
    }

    return Stack(children: [
      CustomScrollView(
          controller: scrollController,
          scrollDirection: Axis.vertical,
          slivers: buildMenuColumn(widget.parent!, context, menuBloc, cWidth, cHeight)),
    ]);
  }

  List<Widget> buildMenuColumn(int parent, BuildContext context, MenuBloc menuBloc, double cWidth, double cHeight) {
    final List<Widget> slivers = [];

    bool isChild = menuBloc.menuTreeRepository.isChildAndGym(menuBloc.parent);
    if (!isChild) {
      slivers.add(getInfoWidget(context, menuBloc));
    } else {
      slivers.add(getFilterWidget(parent, menuBloc));
      slivers.add(getFilterElements(menuBloc));
    }

    final List<Widget> _columnChildren = [];

    if (menuBloc.getFilteredBranch(menuBloc.parent).isEmpty) {
      _columnChildren.add(Container(
          padding: EdgeInsets.only(top: 15.0),
          child: Center(
              child: Stack(alignment: Alignment.bottomLeft, children: [
            Text(AppLocalizations.of(context)!.translate("All Exercises has been filtered out"),
                style: GoogleFonts.inter(color: Colors.white)),
          ]))));
    } else {
      menuBloc.getFilteredBranch(menuBloc.parent).forEach((treeName, value) {
        WorkoutMenuTree workoutTree = value;
        _columnChildren.add(Container(
            padding: EdgeInsets.only(top: 15.0, left: cWidth * 0.04, right: cWidth * 0.04),
            //height: (cHeight / 3) - cWidth * 0.16,
            child: Badge(
                padding: EdgeInsets.all(8),
                position: BadgePosition.bottomEnd(end: 0),
                animationDuration: Duration(milliseconds: 500),
                animationType: BadgeAnimationType.slide,
                badgeColor: Colors.orange[800]!,
                showBadge: workoutTree.base,
                badgeContent: Text(AppLocalizations.of(context)!.translate("base"),
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 12,
                    )),
                child: Stack(alignment: Alignment.bottomLeft, children: [
                  TextButton(
                    child: badgedIcon(workoutTree, cWidth, cHeight),
                    onPressed: () => menuClick(workoutTree, menuBloc),
                  ),
                  Container(
                    padding: EdgeInsets.only(left: 15, bottom: 8, right: 15),
                    child: GestureDetector(
                      onTap: () => menuClick(workoutTree, menuBloc),
                      child: Text(
                        workoutTree.name,
                        maxLines: 4,
                        style: GoogleFonts.archivoBlack(color: workoutTree.color, fontSize: workoutTree.fontSize, height: 1.1),
                      ),
                    ),
                  ),
                ]))));
      });
    }

    _columnChildren.add(SizedBox(
      height: 50,
    ));

    SliverList sliverList = SliverList(
      delegate: SliverChildListDelegate(_columnChildren),
    );
    slivers.add(sliverList);
    return slivers;
  }

  SliverGrid getFilterWidget(int parent, MenuBloc menuBloc) {
    SliverGrid sliverList = SliverGrid(
        delegate: SliverChildListDelegate([
          Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [
            Text(
              AppLocalizations.of(context)!.translate("Equipment Filter"),
              textAlign: TextAlign.center,
              style: GoogleFonts.archivoBlack(
                fontSize: 24,
                color: Colors.white,
                shadows: <Shadow>[
                  Shadow(
                    offset: Offset(5.0, 5.0),
                    blurRadius: 12.0,
                    color: Colors.black54,
                  ),
                  Shadow(
                    offset: Offset(-3.0, 3.0),
                    blurRadius: 12.0,
                    color: Colors.black54,
                  ),
                ],
              ),
            ),
          ])
        ]),
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 1,
          mainAxisSpacing: 5.0,
          crossAxisSpacing: 5.0,
          childAspectRatio: 9,
        ));

    return sliverList;
  }

  SliverGrid getFilterElements(MenuBloc menuBloc) {
    List<Widget> list = [];

    int index = 0;
    menuBloc.exerciseDeviceRepository.getGymDevices().forEach((element) {
      String deviceName = AppLanguage().appLocal == Locale('en') ? element.name : element.nameTranslation;
      ChoiceChip chip = ChoiceChip(
        labelPadding: EdgeInsets.only(right: 3),
        avatar: Icon(
          Icons.remove_circle_outline,
          color: Colors.orange,
          size: 10,
        ),
        label: Text(deviceName),
        labelStyle: TextStyle(fontSize: 9, color: Colors.indigo),
        selectedColor: Colors.white,
        selected: menuBloc.selectedDevice(element.exerciseDeviceId),
        backgroundColor: Colors.blue[100],
        shadowColor: Colors.black54,
        onSelected: (value) => menuBloc.add(MenuFilterExerciseType(deviceId: element.exerciseDeviceId)),
      );
      list.add(chip);
      if (index == 4) {
        list.add(Divider());
      }

      index++;
    });

    SliverGrid sliverList = SliverGrid(
        delegate: SliverChildListDelegate(list),
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 4,
          mainAxisSpacing: 1.5,
          crossAxisSpacing: 1.5,
          childAspectRatio: 2.5,
        ));
    return sliverList;
  }

  SliverAppBar getInfoWidget(BuildContext context, MenuBloc menuBloc) {
    menuBloc.setContext(context);

    SliverAppBar sliverAppBar = SliverAppBar(
        automaticallyImplyLeading: false,
        backgroundColor: Colors.transparent,
        title: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
          !activeExercisePlan
              ? SizedBox(
                  width: 50,
                )
              : SizedBox(
                  width: 10,
                ),
          MenuSearchBar(
            listItems: menuBloc.menuTreeRepository.menuAsExercise,
            onFind: (value) {
              if (Cache().userLoggedIn == null) {
                ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                    backgroundColor: Colors.orange,
                    content: Text(AppLocalizations.of(context)!.translate('Please log in'), style: TextStyle(color: Colors.white))));
              } else {
                Track().track(TrackingEvent.search, eventValue: value!.exerciseType!.name);
                menuBloc.ability = ExerciseAbility.oneRepMax;
                Navigator.of(context).pushNamed('exerciseNewPage', arguments: value.exerciseType);
              }
            },
          ),
          Cache().activeExercisePlan != null
              ? GestureDetector(
                  onTap: () => showDialog(
                      context: context,
                      builder: (BuildContext context) {
                        return DialogCommon(
                          title: t("You have an active Test Set!"),
                          descriptions: Cache().activeExercisePlan!.name,
                          description2: t("Press OK to continue"),
                          text: "OK",
                          onTap: () => {
                            Navigator.of(context).pop(),
                            if (Cache().activeExercisePlan != null)
                              {
                                Navigator.of(context).popAndPushNamed("testSetExecute"),
                              }
                          },
                          onCancel: () => {
                            Navigator.of(context).pop(),
                          },
                        );
                      }),
                  child: AnimatedBuilder(
                      animation: animation,
                      builder: (context, snapshot) {
                        return Center(
                          child: Container(
                            width: animation.value,
                            height: animation.value,
                            child: Image.asset("asset/image/pict_reps_volumen_db.png"),
                          ),
                        );
                      }))
              : Offstage(),
          activeExercisePlan
              ? SizedBox(
                  width: 10,
                )
              : Offstage(),
        ]));
    return sliverAppBar;
  }

  void menuClick(WorkoutMenuTree workoutTree, MenuBloc menuBloc) {
    /* if (tutorialBloc.isActive) {
      final String checkText = workoutTree.nameEnglish;
      if (!tutorialBloc.checkAction(checkText)) {
        return;
      }
    } */
    print("ability: ${menuBloc.ability} tree: $workoutTree parent: ${workoutTree.parent}");

    if (workoutTree.child == false) {
      if (menuBloc.ability != null && ExerciseAbility.mini_test_set.equalsTo(menuBloc.ability!) && workoutTree.parent != 0) {
        HashMap args = HashMap();
        args['templateName'] = workoutTree.nameEnglish;
        args['templateNameTranslation'] = workoutTree.name;
        Navigator.of(context).pushNamed('testSetEdit', arguments: args);
        menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
      } else if (menuBloc.ability != null && ExerciseAbility.training.equalsTo(menuBloc.ability!) && workoutTree.parent != 0) {
        HashMap<String, dynamic> args = HashMap();
        args['parentName'] = workoutTree.internalName;
        Navigator.of(context).pushNamed("myTrainingPlanActivate", arguments: args);
        menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
      } else if (workoutTree.internalName == "training_execute") {
        /* Cache().myTrainingPlan = null;
        Cache().deleteMyTrainingPlan(); */
        if (Cache().myTrainingPlan != null) {
          final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
          bloc.setMyPlan(Cache().myTrainingPlan);
          Navigator.of(context).pushNamed("myTrainingPlanExecute");
        } else {
          showDialog(
              context: context,
              builder: (BuildContext context) {
                return DialogCommon(
                  title: t("No selected Training Plan"),
                  descriptions: t("Based on your initial data, we will generate the personalized training plan for you."),
                  text: "OK",
                  onTap: () {
                    TrainingPlanRepository trainingPlanRepository = TrainingPlanRepository();
                    trainingPlanRepository.generateTrainingPlan();
                    final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
                    bloc.setMyPlan(Cache().myTrainingPlan);
                    Future.delayed(Duration(milliseconds: 1000), () async {
                      Navigator.of(context).pushNamed("myTrainingPlanExecute");
                    });
                  },
                  onCancel: () => {
                    Navigator.of(context).pop(),
                  },
                );
              });
        }
      } else {
        menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
      }
    } else {
      menuBloc.add(MenuClickExercise(exerciseTypeId: workoutTree.id));

      if (workoutTree.exerciseType!.name == "Custom" && Cache().userLoggedIn!.admin == 1) {
        Navigator.of(context).pushNamed('exerciseCustomPage', arguments: workoutTree.exerciseType);
      } else {
        Navigator.of(context).pushNamed('exerciseNewPage', arguments: workoutTree.exerciseType);
      }
    }
  }

  dynamic getShape(WorkoutMenuTree workoutTree) {
    bool base = workoutTree.base;
    dynamic returnCode = (base == true)
        ? RoundedRectangleBorder(
            side: BorderSide(width: 6, color: Colors.orangeAccent), borderRadius: BorderRadius.all(Radius.circular(24.0)))
        : RoundedRectangleBorder(
            side: BorderSide(width: 1, color: Colors.transparent), borderRadius: BorderRadius.all(Radius.circular(8.0)));
    return returnCode;
  }

  Widget badgedIcon(WorkoutMenuTree workoutMenuTree, double cWidth, double cHeight) {
    String badgeKey = workoutMenuTree.nameEnglish;
    bool show = Cache().getBadges()[badgeKey] != null;
    int counter = Cache().getBadges()[badgeKey] != null ? Cache().getBadges()[badgeKey] : 0;
    Widget buttonImage = MenuImage(imageName: workoutMenuTree.imageName, workoutTreeId: workoutMenuTree.id);
    return Badge(
      padding: EdgeInsets.all(8),
      position: BadgePosition.topEnd(top: 3, end: 3),
      animationDuration: Duration(milliseconds: 500),
      animationType: BadgeAnimationType.slide,
      badgeColor: Colors.red,
      showBadge: show,
      badgeContent: Text(counter.toString(),
          style: TextStyle(
            color: Colors.white,
            fontSize: 16,
          )),
      child: buttonImage,
    );
  }

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