import 'dart:async';

import 'package:appinio_swiper/appinio_swiper.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/marathon/marathon_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_model.dart';
import 'package:mohem_flutter_app/models/marathon/question_model.dart';
import 'package:mohem_flutter_app/models/marathon/winner_model.dart';
import 'package:mohem_flutter_app/models/privilege_list_model.dart';
import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart';
import 'package:video_player/video_player.dart';

class MarathonProvider extends ChangeNotifier {
  //****************VARIABLES**********

  final AppinioSwiperController swiperController = AppinioSwiperController();

  MarathonDetailModel marathonDetailModel = MarathonDetailModel();
  List<CardContent> cardContentList = <CardContent>[];
  QuestionModel currentQuestion = QuestionModel();
  List<QuestionCardStatus> answerStatusesList = <QuestionCardStatus>[];
  QuestionCardStatus questionCardStatus = QuestionCardStatus.question;
  List<WinnerModel>? selectedWinners;
  int? selectedOptionIndex;
  String? selectedOptionId;
  int? totalQualifiers;

  //TODO:  THIS BUG NEEDS TO BE FIXED. NOT DONE YET
  String? gapTimeImage;
  String? gapTimeText;
  int? gapTimeType;

  bool iAmWinner = false;
  bool isPrivilegedWithMarathon = false;

  bool _isLoading = false;

  bool get isLoading => _isLoading;

  set isLoading(bool value) {
    _isLoading = value;
    notifyListeners();
  }

  bool _isUpComingMarathon = true;

  bool get isUpComingMarathon => _isUpComingMarathon;

  set isUpComingMarathon(bool value) {
    _isUpComingMarathon = value;
    notifyListeners();
  }

  bool _itsMarathonTime = false;

  bool get itsMarathonTime => _itsMarathonTime;

  set itsMarathonTime(bool value) {
    _itsMarathonTime = value;
    notifyListeners();
  }

  bool _isMarathonCompleted = false;

  bool get isMarathonCompleted => _isMarathonCompleted;

  set isMarathonCompleted(bool value) {
    _isMarathonCompleted = value;
    notifyListeners();
  }

  bool isUserOutOfGame = false;

  set updateIsUserOutOfGame(bool value) {
    isUserOutOfGame = value;
    notifyListeners();
  }

  int _currentQuestionNumber = 0;

  int get currentQuestionNumber => _currentQuestionNumber;

  set currentQuestionNumber(int value) {
    _currentQuestionNumber = value;
    notifyListeners();
  }

  int _totalMarathoners = 0;

  int get totalMarathoners => _totalMarathoners;

  set totalMarathoners(int value) {
    _totalMarathoners = value;
    notifyListeners();
  }

  //****************SPONSOR VIDEO PLAYER**********

  late VideoPlayerController videoController;

  Future<void> initializeVideoPlayer() async {
    videoController = VideoPlayerController.network(ApiConsts.marathonBaseUrlServices + marathonDetailModel.sponsors!.first.video!);
    await videoController.initialize();
    await videoController.play();
    await videoController.setVolume(1.0);
    await videoController.setLooping(false);
    totalSponsorVideoSeconds = videoController.value.duration.inSeconds;
    notifyListeners();
  }

  void disposeVideoPlayer() {
    videoController.dispose();
    notifyListeners();
  }

  //****************TIMERS**********

  int sponsorsSecondsCounter = 0;
  int totalSponsorVideoSeconds = 0;
  Timer timerForSponsorVideo = Timer.periodic(const Duration(seconds: 1), (Timer timer) {});

  void startTimerForSponsorVideo() {
    const Duration oneSec = Duration(seconds: 1);
    timerForSponsorVideo = Timer.periodic(
      oneSec,
      (Timer timer) async {
        sponsorsSecondsCounter++;
        if (totalSponsorVideoSeconds == 0) {
          timer.cancel();
          notifyListeners();
          return;
        } else {
          totalSponsorVideoSeconds--;
        }

        notifyListeners();
      },
    );
  }

  int totalSecondsToWaitForMarathon = 20;
  Timer timerToWaitForMarathon = Timer.periodic(const Duration(seconds: 1), (Timer timer) {});

  void startTimerToWaitForMarathon() {
    const Duration oneSec = Duration(seconds: 1);
    timerToWaitForMarathon = Timer.periodic(
      oneSec,
      (Timer timer) async {
        if (totalSecondsToWaitForMarathon == 0) {
          callNextQuestionApi();
          timer.cancel();
          return;
        } else {
          totalSecondsToWaitForMarathon--;
        }
        notifyListeners();
      },
    );
  }

  int totalCurrentQuestionTime = 0;
  int currentGapTime = 0;
  Timer timerForQuestion = Timer.periodic(const Duration(seconds: 1), (Timer timer) {});

  void startTimerForQuestion() {
    const Duration oneSec = Duration(seconds: 1);
    timerForQuestion = Timer.periodic(
      oneSec,
      (Timer timer) async {
        // This 2 is just to show the color of answer tile for 2 seconds and then update card status
        if (totalCurrentQuestionTime - currentGapTime == 1) {
          getCorrectAnswerAndUpdateAnswerColor();
        }

        if (totalCurrentQuestionTime == currentGapTime) {
          totalCurrentQuestionTime--;

          updateCardStatusToAnswer();

          scheduleMicrotask(() async {
            await callSubmitOptionApi().then((bool value) async {
              if (value) {
                await callNextQuestionApi();
              }
            });
          });
        }

        if (totalCurrentQuestionTime == 0) {
          gapTimeImage = currentQuestion.gapImage;
          gapTimeText = currentQuestion.gapText;
          gapTimeType = currentQuestion.gapType;
          updateCardData();
          if (currentQuestionNumber - 1 == marathonDetailModel.totalQuestions!) {
            callGetQualifiersApi();
            updateQuestionCardStatus(QuestionCardStatus.findingWinner);
            timer.cancel();
            cancelTimer();
            notifyListeners();
          }
          return;
        } else {
          if (totalCurrentQuestionTime != currentGapTime) {
            totalCurrentQuestionTime--;
          }
        }

        notifyListeners();
      },
    );
  }

  int totalSecondsToWaitForWinner = 30;
  Timer timerForWinnerSelection = Timer.periodic(const Duration(seconds: 1), (Timer timer) {});

  void startTimerForWinnerSelection() {
    const Duration oneSec = Duration(seconds: 1);
    timerForWinnerSelection = Timer.periodic(
      oneSec,
      (Timer timer) async {
        if (totalSecondsToWaitForWinner == 0) {
          timer.cancel();
          updateQuestionCardStatus(QuestionCardStatus.winnerFound);
          return;
        } else {
          totalSecondsToWaitForWinner--;
        }

        notifyListeners();
      },
    );
  }

  //****************FUNCTIONS*********

  Future<bool> callSubmitOptionApi() async {
    return await MarathonApiClient().submitSelectedOption(marathonId: marathonDetailModel.id!, questionId: currentQuestion.id, selectedAnswerId: selectedOptionId);
  }

  Future<void> callGetQualifiersApi() async {
    totalQualifiers = await MarathonApiClient().getQualifiers(marathonId: marathonDetailModel.id!);
    notifyListeners();
  }

  Future<void> callGetSelectedWinnersApi() async {
    selectedWinners = await MarathonApiClient().getSelectedWinner(marathonId: marathonDetailModel.id!);
    if (selectedWinners != null) {
      selectedWinners!.removeWhere((WinnerModel element) {
        if (element.employeeId == AppState().memberInformationList!.eMPLOYEENUMBER) {
          iAmWinner = true;
          return true;
        } else {
          return false;
        }
      });
    }

    notifyListeners();
  }

  Future<void> callNextQuestionApi() async {
    if (currentQuestionNumber < marathonDetailModel.totalQuestions!) {
      if (currentQuestionNumber == 0) {
        Utils.showLoading(AppRoutes.navigatorKey.currentContext!);
        currentQuestion = (await MarathonApiClient().getNextQuestion(questionId: null, marathonId: marathonDetailModel.id!))!;
        gapTimeImage = currentQuestion.gapImage;
        gapTimeText = currentQuestion.gapText;
        gapTimeType = currentQuestion.gapType;
        if (Utils.isLoading) {
          Utils.hideLoading(AppRoutes.navigatorKey.currentContext!);
        }
        startTimerForQuestion();
        updateCardData();

        Navigator.pushReplacementNamed(AppRoutes.navigatorKey.currentContext!, AppRoutes.marathonScreen);
      } else {
        currentQuestion = (await MarathonApiClient().getNextQuestion(questionId: currentQuestion.id, marathonId: marathonDetailModel.id!))!;
      }
      notifyListeners();
    }
  }

  void updateCardData() {
    if (currentQuestionNumber > 0) {
      swiperController.swipeLeft();
    }
    selectedOptionIndex = null;
    currentQuestionNumber++;

    cardContentList.add(const CardContent());
    totalCurrentQuestionTime = currentQuestion.questionTime! + currentQuestion.nextQuestGap!;
    currentGapTime = currentQuestion.nextQuestGap!;
    totalMarathoners = currentQuestion.remainingParticipantCount!;
    questionCardStatus = QuestionCardStatus.question;
    notifyListeners();
  }

  void populateQuestionStatusesList() {
    if (marathonDetailModel.totalQuestions != null) {
      for (int i = 0; i < marathonDetailModel.totalQuestions!; i++) {
        answerStatusesList.add(QuestionCardStatus.question);
      }
      notifyListeners();
    }
  }

  void updateAnswerStatusesList(QuestionCardStatus status) {
    answerStatusesList[currentQuestionNumber - 1] = status;
    notifyListeners();
  }

  void addItemToList(CardContent value) {
    cardContentList.add(value);
    notifyListeners();
  }

  void updateCurrentQuestionOptionStatus(QuestionsOptionStatus status, int index) {
    for (int i = 0; i < currentQuestion.questionOptions!.length; i++) {
      currentQuestion.questionOptions![i].optionStatus = QuestionsOptionStatus.unSelected;
    }
    currentQuestion.questionOptions![index].optionStatus = status;
    selectedOptionIndex = index;
    notifyListeners();
  }

  void updateQuestionCardStatus(QuestionCardStatus status) {
    if (status == QuestionCardStatus.wrongAnswer || status == QuestionCardStatus.skippedAnswer) {
      updateIsUserOutOfGame = true;
    }
    questionCardStatus = status;
    notifyListeners();
  }

  void getCorrectAnswerAndUpdateAnswerColor() {
    if (selectedOptionIndex != null) {
      if (currentQuestion.questionOptions![selectedOptionIndex!].isCorrectOption!) {
        updateCurrentQuestionOptionStatus(QuestionsOptionStatus.correct, selectedOptionIndex!);
      } else {
        updateCurrentQuestionOptionStatus(QuestionsOptionStatus.wrong, selectedOptionIndex!);
      }
    }
  }

  void updateCardStatusToAnswer() {
    if (currentQuestionNumber == 0) {
      return;
    }

    if (selectedOptionIndex != null) {
      if (currentQuestion.questionOptions![selectedOptionIndex!].isCorrectOption!) {
        updateQuestionCardStatus(QuestionCardStatus.correctAnswer);
        updateAnswerStatusesList(QuestionCardStatus.correctAnswer);
      } else {
        updateQuestionCardStatus(QuestionCardStatus.wrongAnswer);
        updateAnswerStatusesList(QuestionCardStatus.wrongAnswer);
      }
    } else {
      updateQuestionCardStatus(QuestionCardStatus.skippedAnswer);
      updateAnswerStatusesList(QuestionCardStatus.skippedAnswer);
    }
  }

  void resetValues() async {
    _currentQuestionNumber = 0;
    cardContentList.clear();
    timerForWinnerSelection.cancel();
    timerForSponsorVideo.cancel();
    timerToWaitForMarathon.cancel();
    timerForQuestion.cancel();
    _isMarathonCompleted = false;
    isUserOutOfGame = false;
    totalCurrentQuestionTime = 0;
    sponsorsSecondsCounter = 0;
    totalSponsorVideoSeconds = 0;
    totalSecondsToWaitForMarathon = 20;
    currentGapTime = 0;
    currentQuestion = QuestionModel();
    notifyListeners();
  }

  void cancelTimer() {
    timerForQuestion.cancel();
    notifyListeners();
  }

  bool checkIfPrivilegedForMarathon() {
    return true;
    for (PrivilegeListModel element in AppState().privilegeListModel!) {
      if (element.serviceName == "Marathon") {
        if (element.previlege != null) {
          return element.previlege!;
        }
      }
    }
    return false;
  }

  Future<void> getMarathonDetailsFromApi() async {
    isLoading = true;
    notifyListeners();
    isPrivilegedWithMarathon = checkIfPrivilegedForMarathon();
    if (isPrivilegedWithMarathon) {
      await MarathonApiClient().getMarathonToken().whenComplete(() async {
        marathonDetailModel = await MarathonApiClient().getMarathonDetails();
        if (marathonDetailModel.id == null) {
          isUpComingMarathon = false;
          isLoading = false;
          notifyListeners();
          return;
        }
        populateQuestionStatusesList();
      });
    }
    isLoading = false;
    notifyListeners();
  }

  Future<void> onJoinMarathonPressed(BuildContext context) async {
    try {
      Utils.showLoading(context);
      resetValues();
      int? remainingTime = await MarathonApiClient().joinMarathonAsParticipant();
      if (remainingTime != null) {
        totalSecondsToWaitForMarathon = remainingTime;
        notifyListeners();
        startTimerToWaitForMarathon();
        Navigator.pushReplacementNamed(context, AppRoutes.marathonWaitingScreen);
      }
    } catch (e) {
      Utils.hideLoading(context);
      Utils.confirmDialog(context, e.toString());
    }
  }
}
