import 'dart:async';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/tutorial.dart';
import 'package:aitrainer_app/model/tutorial_step.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

part 'tutorial_event.dart';
part 'tutorial_state.dart';

class TutorialBloc extends Bloc<TutorialEvent, TutorialState> with Logging {
  late String tutorialName;
  final double mediaHeightBase = 675;
  bool isActive = false;
  bool canActivate = false;

  Tutorial? tutorial;
  String? actualText;
  String? actualCheck;

  List<String> checks = [];

  double calculatedHeight = 0;

  TutorialStepAction? action;
  double? top;
  double left = 20;
  bool showCheckText = true;
  int parent = 0;

  int step = 0;

  MenuBloc? menuBloc;

  TutorialBloc({required this.tutorialName}) : super(TutorialInitial());

  init() {
    if (Cache().tutorials != null) {
      final List<Tutorial> tutorials = Cache().tutorials!;
      tutorials.forEach((element) {
        final String realTutorialName = tutorialName.replaceFirst("tutorial", "").toLowerCase();
        if (element.name.toLowerCase() == realTutorialName) {
          tutorial = element;

          setNextStepData(step);
          isActive = true;
          canActivate = true;
        }
      });
    }
  }

  void setNextStepData(int step) {
    if (step == -1) {
      isActive = false;
      return;
    }
    if (tutorial != null && tutorial!.steps != null) {
      actualText = tutorial!.steps![step].tutorialTextTranslation;

      this.actualCheck = tutorial!.steps![step].checkText;

      this.checks = [];

      if (this.actualCheck != null) {
        this.checks = this.actualCheck!.split("|");
      } else {
        this.checks.add("Next");
      }

      if (this.tutorial!.steps![step].action != null) {
        this.action = this.tutorial!.steps![step].action;
        this.top = action!.top.toDouble();
        this.left = action!.left == -1 ? 20 : action!.left.toDouble();
        this.showCheckText = action!.showCheckText == true;
        this.parent = action!.parent;
      }
    }
  }

  bool isTutorialDone() {
    ActivityDone? activityDone = ActivityDone.tutorialBasic.searchByString(tutorialName);

    if (activityDone == null) {
      return true;
    }
    bool? isActivityDone = Cache().activitiesDone[activityDone.toStr()];

    if (isActivityDone == null || isActivityDone == true) {
      return true;
    }
    canActivate = true;
    return false;
  }

  bool activateTutorial() {
    if (isTutorialDone()) {
      isActive = false;
      canActivate = false;
      return false;
    }

    init();
    return true;
  }

  int getElementCount(String elem) {
    int pos = 0;
    int count = 0;
    bool out = false;
    while (out == false) {
      pos = actualText!.indexOf(elem, pos);
      if (pos == -1) {
        out = true;
      } else {
        count++;
        pos++;
      }
    }
    return count;
  }

  int getNextStep(int step) {
    int next = 0;
    if (action == null) {
      return step + 1;
    }
    step++;
    next = step;
    print("Next step:! $step");
    if (step >= tutorial!.steps!.length) {
      next = -1;
      this.add(TutorialFinished());
    }
    return next;
  }

  bool checkAction(String checkText) {
    final bool nextStep = checkText == actualCheck;
    if (nextStep) {
      this.add(TutorialNext(text: actualCheck!));
    }
    return nextStep;
  }

  @override
  Stream<TutorialState> mapEventToState(TutorialEvent event) async* {
    if (event is TutorialLoad) {
      init();
      if (menuBloc != null) {
        menuBloc!.add(MenuCreate());
      }
    } else if (event is TutorialNext) {
      print("Tutorial Next: ${event.text}");
      if (tutorial != null) {
        yield TutorialLoading();

        step = this.getNextStep(step);
        if (step == -1) {
          print("Tutorial $tutorialName finished!");
          return;
        }
        print("Step: $step");
        setNextStepData(step);

        if (menuBloc != null) {
          menuBloc!.add(MenuCreate());
        }
        Track().track(TrackingEvent.tutorial_step, eventValue: step.toString());
        yield TutorialReady();
      }
    } else if (event is TutorialWrongAction) {
      yield TutorialLoading();
      actualText = tutorial!.steps![step].errorTextTranslation!;
      yield TutorialReady();
    } else if (event is TutorialStart) {
      yield TutorialLoading();
      canActivate = true;
      step = 0;
      yield TutorialReady();
    } else if (event is TutorialFinished) {
      yield TutorialLoading();
      isActive = false;
      canActivate = false;
      ActivityDone? activityDone = ActivityDone.tutorialBasic.searchByString(tutorialName);
      if (activityDone != null) {
        await Cache().setActivityDonePrefs(activityDone);
      }
      Track().track(TrackingEvent.tutorial_finished);
      yield TutorialReady();
    }
  }
}
