import 'dart:collection';
import 'dart:math' show pi;
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/dialog_html.dart';

import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:badges/badges.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:extended_tabs/extended_tabs.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';

class TrainingPlanExecute extends StatefulWidget {
  const TrainingPlanExecute({Key? key}) : super(key: key);

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

class _TrainingPlanExecuteState extends State<TrainingPlanExecute> with Trans {
  @override
  Widget build(BuildContext context) {
    final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
    bloc.activateDays();

    setContext(context);
    return Scaffold(
      appBar: AppBarNav(
        depth: 0,
      ),
      body: Container(
        padding: EdgeInsets.all(0),
        decoration: BoxDecoration(
          image: DecorationImage(
            image: AssetImage('asset/image/WT_black_background.jpg'),
            fit: BoxFit.cover,
            alignment: Alignment.center,
          ),
        ),
        child: BlocConsumer<TrainingPlanBloc, TrainingPlanState>(listener: (context, state) {
          if (state is TrainingPlanError) {
            showDialog(
                context: context,
                builder: (BuildContext context) {
                  return DialogCommon(
                    warning: true,
                    title: t("Warning"),
                    descriptions: t(state.message),
                    text: "OK",
                    onTap: () => Navigator.of(context).pop(),
                    onCancel: () => {
                      Navigator.of(context).pop(),
                    },
                  );
                });
          } else if (state is TrainingPlanDayFinished) {
            bloc.celebrating = false;
            final HashMap args = HashMap();
            args["bloc"] = bloc;
            args["day"] = bloc.dayNames[bloc.activeDayIndex];
            Navigator.of(context).pushNamed('myTrainingEvaluation', arguments: args);
          } else if (state is TrainingPlanDayReadyToRestart) {
            if (!bloc.celebrating) {
              showCupertinoDialog(
                  useRootNavigator: true,
                  context: context,
                  builder: (_) => CupertinoAlertDialog(
                        title: Text(t("The training is finished")),
                        content: Column(children: [Divider(), Text(t("Do you want to restart, or select a new Training Plan?"))]),
                        actions: [
                          TextButton(
                              child: Text(t("New Training Plan"), textAlign: TextAlign.center),
                              onPressed: () => {
                                    Navigator.pop(context),
                                    Navigator.of(context).popAndPushNamed('myTrainingPlans'),
                                    bloc.restarting = false,
                                  }),
                          TextButton(
                            child: Text(t("Restart")),
                            onPressed: () {
                              bloc.restart();
                              Navigator.pop(context);
                              Navigator.of(context).popAndPushNamed('home');
                            },
                          )
                        ],
                      ));
            }
          }
        }, builder: (context, state) {
          return ModalProgressHUD(
            child: ExerciseTabs(bloc: bloc),
            inAsyncCall: state is TrainingPlanLoading,
            opacity: 0.5,
            color: Colors.black54,
            progressIndicator: CircularProgressIndicator(),
          );
        }),
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: () {
          final HashMap args = HashMap();
          args["bloc"] = bloc;
          args["day"] = bloc.dayNames[bloc.activeDayIndex];
          bloc.getNext() != null
              ? _ExerciseListState.executeExercise(bloc, bloc.getNext()!, context)
              : Navigator.of(context).pushNamed('myTrainingEvaluation', arguments: args);
        },
        backgroundColor: Colors.orange[600], //Color(0xffb4f500),
        icon: Icon(
          CustomIcon.weight_hanging,
          color: Colors.black,
        ),
        label: Text(
          t("Next Exercise"),
          style: GoogleFonts.inter(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 16),
        ),
      ),
    );
  }
}

class ExerciseTabs extends StatefulWidget {
  final TrainingPlanBloc bloc;
  ExerciseTabs({required this.bloc});
  @override
  _ExerciseTabs createState() => _ExerciseTabs();
}

class _ExerciseTabs extends State<ExerciseTabs> with TickerProviderStateMixin {
  late TabController tabController;

  @override
  void initState() {
    super.initState();
    tabController = TabController(length: widget.bloc.dayNames.length, vsync: this);
    tabController.animateTo(widget.bloc.activeDayIndex, duration: Duration(milliseconds: 300));
  }

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

  @override
  Widget build(BuildContext context) {
    return getTabs(widget.bloc);
  }

  Widget getTabs(TrainingPlanBloc bloc) {
    final String tabName = bloc.getMyPlan() != null && bloc.getMyPlan()!.name != null ? bloc.getMyPlan()!.name! : "";
    return Column(children: [
      Text(
        tabName,
        style: GoogleFonts.archivoBlack(
          fontSize: 14,
          color: Colors.white,
          shadows: <Shadow>[
            Shadow(
              offset: Offset(2.0, 2.0),
              blurRadius: 6.0,
              color: Colors.black87,
            ),
            Shadow(
              offset: Offset(2.0, 2.0),
              blurRadius: 6.0,
              color: Colors.black87,
            ),
          ],
        ),
      ),
      ExtendedTabBar(
        indicator: BoxDecoration(
            color: Colors.black87,
            border: Border(
              bottom: BorderSide(width: 4.0, color: Color(0xffb4f500)),
              // top: BorderSide(width: 4.0, color: Colors.blue),
            )),
        labelPadding: EdgeInsets.only(left: 0, right: 0),
        tabs: getTabNames(),
        controller: tabController,
        onTap: (index) => bloc.activeDayIndex = index,
      ),
      Expanded(
          child: ExtendedTabBarView(
        children: getExerciseLists(),
        controller: tabController,

        /// if link is true and current tabbarview over scroll,
        /// it will check and scroll ancestor or child tabbarView.
        link: true,

        /// cache page count
        /// default is 0.
        /// if cacheExtent is 1, it has two pages in cache
        /// null is infinity, it will cache all pages
        cacheExtent: 0,
      )),
    ]);
  }

  List<Tab> getTabNames() {
    List<Tab> tabs = [];
    final int tabCount = widget.bloc.dayNames.length;
    double cWidth = MediaQuery.of(context).size.width;
    widget.bloc.dayNames.forEach((element) {
      final Widget widget = Container(
          //height: 40,
          padding: EdgeInsets.only(top: 3, left: 10, right: 10, bottom: 3),
          width: (cWidth / tabCount),
          color: Colors.white10,
          child: RichText(
              textScaleFactor: 0.8,
              text: TextSpan(
                  style: GoogleFonts.inter(
                    fontSize: 14,
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                  children: [
                    TextSpan(
                        text: AppLocalizations.of(context)!.translate("Training Day") + ": \n",
                        style: GoogleFonts.inter(
                          fontSize: 14,
                          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,
                            ),
                          ],
                        )),
                    TextSpan(
                        text: element,
                        style: GoogleFonts.inter(
                          fontSize: 14,
                          fontWeight: FontWeight.bold,
                          color: Color(0xffb4f500),
                          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,
                            ),
                          ],
                        )),
                  ])));

      tabs.add(Tab(child: widget));
    });
    return tabs;
  }

  List<Widget> getExerciseLists() {
    List<Widget> list = [];
    widget.bloc.dayNames.forEach((element) {
      list.add(ExerciseList(bloc: widget.bloc, dayName: element));
    });
    return list;
  }
}

class ExerciseList extends StatefulWidget {
  final TrainingPlanBloc bloc;
  final String dayName;
  ExerciseList({required this.bloc, required this.dayName});

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

class _ExerciseListState extends State<ExerciseList> with Trans {
  final scrollController = ScrollController();
  double offset = 5;

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      animate();
    });
    super.initState();
  }

  @override
  void didUpdateWidget(ExerciseList page) {
    super.didUpdateWidget(page);
    WidgetsBinding.instance.addPostFrameCallback((_) {
      animate();
    });
  }

  void animate() {
    offset = widget.bloc.getOffset();
    if (scrollController.hasClients) {
      scrollController.animateTo(offset, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
    }
  }

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

  static void executeExercise(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail, BuildContext context) {
    CustomerTrainingPlanDetails? next = bloc.getNext();

    if (next != null) {
      String title = "";
      String description = "";
      String description2 = "";
      if (next.exerciseTypeId != detail.exerciseTypeId) {
        title = AppLocalizations.of(context)!.translate("Stop!");
        description = AppLocalizations.of(context)!.translate("Please continue with the next exercise in the queue:") +
            next.exerciseType!.nameTranslation;
      } else {
        final HashMap args = HashMap();
        args['exerciseType'] = next.exerciseType;
        args['customerTrainingPlanDetails'] = detail;
        bloc.backupDetail(detail);
        Navigator.of(context).pushNamed('myTrainingPlanExercise', arguments: args);
        return;
      }

      showDialog(
          context: context,
          barrierDismissible: false,
          builder: (BuildContext context) {
            return DialogCommon(
              title: title,
              descriptions: description,
              description2: description2,
              text: "OK",
              onTap: () => {Navigator.of(context).pop()},
              onCancel: () => {Navigator.of(context).pop()},
            );
          });
    } else {
      Navigator.of(context).pushNamed('home');
    }
  }

  @override
  Widget build(BuildContext context) {
    setContext(context);
    return CustomScrollView(controller: scrollController, slivers: [
      SliverList(delegate: SliverChildListDelegate(getTiles(widget.bloc))),
    ]);
  }

  List<Widget> getTiles(TrainingPlanBloc bloc) {
    List<Widget> tiles = [];

    tiles.addAll(getExerciseTiles(bloc, context));

    return tiles;
  }

  List<Widget> getExerciseTiles(TrainingPlanBloc bloc, BuildContext context) {
    List<Widget> tiles = [];
    CustomerTrainingPlanDetails? prev;
    if (bloc.getMyPlan() != null &&
        bloc.getMyPlan()!.details.isNotEmpty &&
        bloc.getMyPlan()!.days[widget.dayName] != null &&
        bloc.getMyPlan()!.days[widget.dayName]!.isNotEmpty) {
      bloc.getMyPlan()!.days[widget.dayName]!.forEach((element) {
        if (prev == null || (prev != null && prev!.exerciseTypeId != element.exerciseTypeId)) {
          tiles.add(GestureDetector(
              onTap: () =>
                  bloc.getNext() != null ? executeExercise(bloc, bloc.getNext()!, context) : Navigator.of(context).pushNamed('home'),
              child: ExerciseTile(
                bloc: bloc,
                detail: element,
              )));
        }
        prev = element;
      });
    }

    return tiles;
  }
}

// ignore: must_be_immutable
class ExerciseTile extends StatelessWidget with Trans {
  final TrainingPlanBloc bloc;
  final CustomerTrainingPlanDetails detail;

  ExerciseTile({required this.bloc, required this.detail});

  Widget getExerciseQuantities(CustomerTrainingPlanDetails detail, int step, bool noFilter, int highlightStep) {
    bool skipped = detail.state == ExercisePlanDetailState.skipped;
    String quantities = "";
    List<TextSpan> spans = [];
    if (detail.exerciseType!.name == "Warming Up") {
      quantities = t("Min. 10 minutes");
      spans.add(
        TextSpan(text: quantities),
      );
    } else if (detail.exerciseType!.name == "Stretching") {
      quantities = t("Recommended");
      spans.add(
        TextSpan(text: quantities),
      );
    } else {
      List<CustomerTrainingPlanDetails> details = bloc.getAllDetailsSameExercise(detail);
      int index = 0;
      bool isWeight = true;
      details.forEach((element) {
        quantities = "";

        if (index > 0) {
          spans.add(
            TextSpan(text: ", "),
          );
        }
        //print("STEP $step highlight: $highlightStep index: $index");
        if (element.set! > 1) {
          spans.add(
            TextSpan(
                text: (element.exercises.length + 1).toString(),
                style: GoogleFonts.archivoBlack(
                  color: highlightStep == index && noFilter ? Colors.orange[600] : Colors.white,
                )),
          );
          spans.add(
            TextSpan(text: "/${element.set} x "),
          );
        }

        if (element.repeats == -1) {
          quantities += " MAX ";
        } else {
          quantities += "${element.repeats}";
        }

        if (element.exerciseType!.unitQuantityUnit != null && element.weight != null) {
          quantities += "x";
          if (element.weight == -1 || element.weight == -2 || element.weight == -3) {
            quantities += "? kg";
          } else {
            num weight = element.weight! % element.weight!.round() == 0 ? element.weight!.round() : element.weight!;

            quantities += "$weight kg";
          }
        } else {
          isWeight = false;
        }
        if (highlightStep == index && noFilter) {
          spans.add(
            TextSpan(
              text: quantities,
              style: GoogleFonts.archivoBlack(
                color: Colors.orange[600],
              ),
            ),
          );
        } else {
          spans.add(
            TextSpan(text: quantities),
          );
        }
        index++;
      });
      if (isWeight) {
        quantities += " kg";
      }
    }

    return RichText(
      text: TextSpan(
          style: GoogleFonts.archivoBlack(
            fontSize: 20,
            color: skipped ? Colors.grey : Colors.white,
            shadows: <Shadow>[
              Shadow(
                offset: Offset(2.0, 2.0),
                blurRadius: 6.0,
                color: Colors.black87,
              ),
              Shadow(
                offset: Offset(2.0, 2.0),
                blurRadius: 6.0,
                color: Colors.black87,
              ),
            ],
          ),
          children: spans),
    );
  }

  @override
  Widget build(BuildContext context) {
    setContext(context);
    //print("Display Exercise: ${detail.exerciseTypeId}");
    return CarouselSlider(
      options: CarouselOptions(
        viewportFraction: 1,
        reverse: false,
        enableInfiniteScroll: false,
        autoPlay: false,
        aspectRatio: 1.28,
        enlargeCenterPage: false,
        onPageChanged: (index, reason) {
          if (detail.exercises.length == 0) {
            int alternateIndex = index;
            if (alternateIndex >= bloc.alternatives[detail.customerTrainingPlanDetailsId].length) {
              alternateIndex = 0;
            }
            CustomerTrainingPlanDetails? alternate = bloc.alternatives[detail.customerTrainingPlanDetailsId][alternateIndex];
            if (alternate != null) {
              bloc.add(TrainingPlanAlternateChange(detail: alternate, index: alternateIndex));
            }
          } else {
            bloc.add(TrainingPlanCreateException(message: t("This exericise has already been begun")));
          }
        },
      ),
      items: getExerciseTiles(detail),
    );
  }

  List<Widget> getExerciseTiles(CustomerTrainingPlanDetails detail) {
    final List<Widget> list = [];
    if (bloc.alternatives[detail.customerTrainingPlanDetailsId] != null &&
        bloc.alternatives[detail.customerTrainingPlanDetailsId].length > 0) {
      int index = 0;
      for (CustomerTrainingPlanDetails alternative in bloc.alternatives[detail.customerTrainingPlanDetailsId]) {
        final Widget widget = getTile(alternative, index);
        list.add(widget);
        index++;
      }
    }

    return list;
  }

  Widget getTile(CustomerTrainingPlanDetails detail, int index) {
    final CustomerTrainingPlanDetails? next = bloc.getNext();
    final bool noFilter = next != null && next.exerciseTypeId == detail.exerciseTypeId;
    final bool done = bloc.isAllDetailsSameExerciseFinished(detail);
    final bool buddyWarning = detail.exerciseType == null ? false : detail.exerciseType!.buddyWarning;
    final int step = bloc.getStep(detail);
    final int highlightStep = bloc.getHighlightStep(detail);
    final bool hasLeftAlternative = detail.alternatives.length > 0 && index > 0;
    final bool hasRightAlternative =
        detail.alternatives.length > 0 && index + 1 < bloc.alternatives[detail.customerTrainingPlanDetailsId].length;

    return Container(
        child: Stack(alignment: Alignment.centerRight, children: [
      Stack(alignment: Alignment.centerLeft, children: [
        Stack(alignment: Alignment.bottomLeft, children: [
          Badge(
              elevation: 0,
              padding: EdgeInsets.all(0),
              position: BadgePosition.topEnd(top: 5, end: 5),
              animationDuration: Duration(milliseconds: 1500),
              animationType: BadgeAnimationType.fade,
              badgeColor: Colors.transparent,
              showBadge: noFilter || done,
              badgeContent: IconButton(
                  iconSize: 36,
                  onPressed: () => !done ? skip() : {},
                  icon: Icon(
                    done ? CustomIcon.ok_circled : Icons.cancel,
                    color: done ? Colors.green[600] : Colors.red[600],
                  )),
              child: Badge(
                  elevation: 0,
                  padding: EdgeInsets.all(0),
                  position: BadgePosition.topStart(top: 5, start: 5),
                  animationDuration: Duration(milliseconds: 1000),
                  animationType: BadgeAnimationType.scale,
                  badgeColor: Colors.transparent,
                  showBadge: true,
                  badgeContent: IconButton(
                      iconSize: 36,
                      onPressed: () => showDialog(
                          context: context,
                          builder: (BuildContext context) {
                            return DialogHTML(
                                title: detail.exerciseType!.nameTranslation,
                                htmlData: '<p>' + detail.exerciseType!.descriptionTranslation + '</p>');
                          }),
                      icon: Icon(
                        Icons.info_outline,
                        color: Colors.yellow[200],
                      )),
                  child: Badge(
                      elevation: 0,
                      padding: EdgeInsets.all(0),
                      position: BadgePosition.topEnd(top: 5, end: 60),
                      animationDuration: Duration(milliseconds: 500),
                      animationType: BadgeAnimationType.fade,
                      badgeColor: Colors.transparent,
                      showBadge: buddyWarning,
                      badgeContent: IconButton(
                          iconSize: 36,
                          onPressed: () => showDialog(
                              context: context,
                              builder: (BuildContext context) {
                                return DialogCommon(
                                  warning: true,
                                  text: "Warning",
                                  descriptions: t("Attention!"),
                                  description2: t("The safe and exact execution of this exercise you need a training buddy or a trainer"),
                                  description3: t("Execution at your own risk!"),
                                  onTap: () => Navigator.of(context).pop(),
                                  onCancel: () => Navigator.of(context).pop(),
                                  title: t('Training Buddy'),
                                );
                              }),
                          icon: Icon(
                            CustomIcon.exclamation_circle,
                            color: Colors.red[800],
                          )),
                      child: Column(children: [
                        MenuImage(
                          imageName: bloc.getActualImageName(detail.exerciseType!.exerciseTypeId),
                          workoutTreeId: bloc.getActualWorkoutTreeId(detail.exerciseType!.exerciseTypeId)!,
                          radius: 0,
                          filter: !noFilter,
                        ),
                        Container(
                          padding: EdgeInsets.only(left: 20, top: 10, bottom: 0),
                          decoration: BoxDecoration(
                            image: DecorationImage(
                              image: AssetImage('asset/image/WT_zold.jpg'),
                              fit: BoxFit.cover,
                              alignment: Alignment.center,
                            ),
                          ),
                          foregroundDecoration: !noFilter
                              ? BoxDecoration(
                                  color: Colors.black38,
                                  backgroundBlendMode: BlendMode.darken,
                                )
                              : null,
                          height: 80,
                          width: double.infinity,
                          child: getExerciseQuantities(detail, step, noFilter, highlightStep),
                        )
                      ])))),
          Container(
            padding: EdgeInsets.only(left: 15, bottom: 80, right: 15),
            width: double.infinity,
            color: Colors.transparent,
            child: Text(
              detail.exerciseType!.nameTranslation,
              maxLines: 3,
              style: GoogleFonts.archivoBlack(
                color: noFilter ? Colors.white : Colors.grey,
                fontSize: 36,
                height: 1.1,
                shadows: <Shadow>[
                  Shadow(
                    offset: Offset(8.0, 8.0),
                    blurRadius: 8.0,
                    color: Colors.black54,
                  ),
                  Shadow(
                    offset: Offset(8.0, 8.0),
                    blurRadius: 8.0,
                    color: Colors.black54,
                  ),
                ],
              ),
            ),
          ),
        ]),
        hasLeftAlternative
            ? Positioned(
                top: 50,
                child: Image.asset(
                  'asset/image/alternatives_arrow.png',
                  height: 100,
                  width: 100,
                  color: noFilter ? Color(0xffb4f500) : Colors.grey,
                ))
            : Offstage(),
      ]),
      hasRightAlternative
          ? Positioned(
              top: 50,
              child: Transform.rotate(
                  angle: pi,
                  alignment: Alignment.center,
                  child: Image.asset(
                    'asset/image/alternatives_arrow.png',
                    height: 100,
                    width: 100,
                    color: noFilter ? Color(0xffb4f500) : Colors.grey,
                  )),
            )
          : Offstage(),
    ]));
  }

  void skip() {
    showCupertinoDialog(
        useRootNavigator: true,
        context: context,
        builder: (_) => CupertinoAlertDialog(
              title: Text(t("You want to skip really the entire exercise?")),
              content: Column(children: [
                Divider(),
              ]),
              actions: [
                TextButton(
                    child: Text(t("No")),
                    onPressed: () => {
                          Navigator.pop(context),
                        }),
                TextButton(
                  child: Text(t("Yes")),
                  onPressed: () {
                    Navigator.pop(context);
                    bloc.add(TrainingPlanSkipEntireExercise(detail: detail));
                  },
                )
              ],
            ));
  }
}
