import 'package:english_learning/features/learning/modules/exercises/models/review_exercise_model.dart';
import 'package:english_learning/features/learning/modules/feedback/models/feedback_model.dart';
import 'package:flutter/material.dart';
import 'package:english_learning/core/services/repositories/exercise_repository.dart';
import 'package:english_learning/features/auth/provider/user_provider.dart';
import 'package:english_learning/features/learning/modules/exercises/models/exercise_model.dart';

class ExerciseProvider extends ChangeNotifier {
  // Dependencies
  final ExerciseRepository _repository;
  final UserProvider _userProvider;

  // Constructor
  ExerciseProvider(this._repository, this._userProvider);

  // State variables
  List<ExerciseModel> _exercises = [];
  List<ReviewExerciseDetail> _reviewExercises = [];
  ReviewExerciseModel? _reviewData;
  Map<int, List<Map<String, String>>> _matchingAnswers = {};
  List<String> _answers = [];
  List<List<Color>> _leftColors = [];
  List<List<Color?>> _rightColors = [];
  int _currentExerciseIndex = 0;
  bool _isLoading = false;
  String _nameTopic = '';
  String _nameLevel = '';
  String? _activeLeftOption;
  String? _studentLearningId;
  List<List<dynamic>> _shuffledRightPairsList = [];
  List<List<dynamic>> _savedShuffledRightPairsList = [];

  // Constants
  final List<Color> _pairColors = [
    Colors.blue,
    Colors.green,
    Colors.orange,
    Colors.purple,
    Colors.red,
  ];

  // Getters
  List<ExerciseModel> get exercises => _exercises;
  List<String> get answers => _answers;
  int get currentExerciseIndex => _currentExerciseIndex;
  bool get isLoading => _isLoading;
  String get nameTopic => _nameTopic;
  String get nameLevel => _nameLevel;
  String? get activeLeftOption => _activeLeftOption;
  String? get studentLearningId => _studentLearningId;
  List<ReviewExerciseDetail> get reviewExercises => _reviewExercises;
  List<List<dynamic>> get shuffledRightPairsList => _shuffledRightPairsList;
  List<List<dynamic>> get savedShuffledRightPairsList =>
      _savedShuffledRightPairsList;

  // Initialization methods
  void initializeAnswers() {
    _answers = List.generate(_exercises.length, (index) => '');
    _matchingAnswers = {};
    _leftColors = List.generate(_exercises.length, (index) {
      if (_exercises[index].choices is MatchingPair) {
        return List.generate(
            (_exercises[index].choices as MatchingPair).pairs.length,
            (i) => _pairColors[i % _pairColors.length]);
      }
      return [];
    });
    _rightColors = List.generate(_exercises.length, (index) {
      if (_exercises[index].choices is MatchingPair) {
        return List<Color?>.filled(
            (_exercises[index].choices as MatchingPair).pairs.length, null);
      }
      return [];
    });
  }

  // Method untuk menyimpan urutan acak saat submit
  void saveShuffledRightPairs() {
    _savedShuffledRightPairsList = List.from(_shuffledRightPairsList);
  }

  // Method untuk mengatur ulang urutan acak saat review
  void restoreShuffledRightPairs() {
    if (_savedShuffledRightPairsList.isNotEmpty) {
      _shuffledRightPairsList = List.from(_savedShuffledRightPairsList);
    }
  }

  void initializeShuffledRightPairs(List<ExerciseModel> exercises) {
    // Hanya acak sekali saat pertama kali membuka level
    if (_shuffledRightPairsList.isEmpty) {
      _shuffledRightPairsList = exercises.map((exercise) {
        if (exercise.choices is MatchingPair) {
          final pairs = (exercise.choices as MatchingPair).pairs;
          final rightPairs = pairs.map((pair) => pair.right).toList();

          // Buat salinan dan acak
          final shuffledPairs = List.from(rightPairs)..shuffle();
          return shuffledPairs;
        }
        return [];
      }).toList();
    }
  }

  // // Answer handling methods
  // void answerQuestion(int index, String answer) {
  //   if (index >= 0 && index < _answers.length) {
  //     if (_exercises[index].choices is MatchingPair) {
  //       _handleMatchingPairAnswer(index, answer);
  //     } else {
  //       _answers[index] = _answers[index] == answer ? '' : answer;
  //     }
  //     notifyListeners();
  //   }
  // }
  void answerQuestion(int index, String answer) {
    if (index >= 0 && index < _answers.length) {
      if (_exercises[index].choices is MatchingPair) {
        _handleMatchingPairAnswer(index, answer);
      } else if (_exercises[index].choices is MultipleChoice) {
        // Store the letter index (e.g., "A", "B", "C", etc.)
        final multipleChoice = _exercises[index].choices as MultipleChoice;
        final options = [
          multipleChoice.optionA,
          multipleChoice.optionB,
          multipleChoice.optionC,
          multipleChoice.optionD,
          multipleChoice.optionE,
        ];
        final optionIndex = options.indexOf(answer);
        if (optionIndex != -1) {
          _answers[index] = String.fromCharCode(65 + optionIndex);
        }
      } else if (_exercises[index].choices is TrueFalse) {
        // Store "1" for true and "0" for false
        // _answers[index] = answer.toLowerCase() == 'true' ? '1' : '0';
        _answers[index] = answer;
      } else {
        _answers[index] = _answers[index] == answer ? '' : answer;
      }
      notifyListeners();
    }
  }

  bool hasMatchedPair(int exerciseIndex, String rightOption) {
    if (!_matchingAnswers.containsKey(exerciseIndex)) return false;
    return _matchingAnswers[exerciseIndex]!
        .any((pair) => pair['right'] == rightOption);
  }

  String? getMatchedLeftPair(int exerciseIndex, String rightOption) {
    if (!_matchingAnswers.containsKey(exerciseIndex)) return null;
    final matchedPair = _matchingAnswers[exerciseIndex]!.firstWhere(
        (pair) => pair['right'] == rightOption,
        orElse: () => {'left': '', 'right': ''});
    return matchedPair['left']!.isEmpty ? null : matchedPair['left'];
  }

  void _handleMatchingPairAnswer(int exerciseIndex, String option) {
    final matchingPair = _exercises[exerciseIndex].choices as MatchingPair;
    final isLeft = matchingPair.pairs.any((pair) => pair.left == option);

    if (isLeft) {
      _selectLeftOption(exerciseIndex, option);
    } else {
      _selectRightOption(exerciseIndex, option);
    }

    _updateMatchingPairAnswer(exerciseIndex);
    notifyListeners();
  }

  void _selectLeftOption(int exerciseIndex, String option) {
    if (_activeLeftOption == option) {
      _activeLeftOption = null;
    } else {
      _activeLeftOption = option;
    }
  }

  void _selectRightOption(int exerciseIndex, String option) {
    if (_activeLeftOption == null) {
      print("Please select a left option first.");
      return;
    }

    if (!_matchingAnswers.containsKey(exerciseIndex)) {
      _matchingAnswers[exerciseIndex] = [];
    }

    // Remove any existing matches for this left or right option
    _matchingAnswers[exerciseIndex]!.removeWhere(
        (pair) => pair['left'] == _activeLeftOption || pair['right'] == option);

    // Add the new pair
    _matchingAnswers[exerciseIndex]!
        .add({'left': _activeLeftOption!, 'right': option});

    // Reset active left option
    _activeLeftOption = null;
  }

  void _updateMatchingPairAnswer(int exerciseIndex) {
    if (_matchingAnswers[exerciseIndex] != null &&
        _matchingAnswers[exerciseIndex]!.length ==
            (_exercises[exerciseIndex].choices as MatchingPair).pairs.length) {
      _answers[exerciseIndex] = _matchingAnswers[exerciseIndex]!
          .map((pair) => "${pair['left']}-${pair['right']}")
          .join(", ");
    } else {
      _answers[exerciseIndex] = '';
    }
  }

  // Utility methods
  bool isAllPairsMatched(int exerciseIndex) {
    if (_exercises[exerciseIndex].choices is! MatchingPair) return false;
    final matchingPair = _exercises[exerciseIndex].choices as MatchingPair;
    return _matchingAnswers[exerciseIndex] != null &&
        _matchingAnswers[exerciseIndex]!.length == matchingPair.pairs.length &&
        _matchingAnswers[exerciseIndex]!.every(
            (pair) => pair['left']!.isNotEmpty && pair['right']!.isNotEmpty);
  }

  String? getMatchingAnswer(int exerciseIndex, int pairIndex, bool isLeft) {
    if (_matchingAnswers.containsKey(exerciseIndex) &&
        pairIndex < _matchingAnswers[exerciseIndex]!.length) {
      return _matchingAnswers[exerciseIndex]![pairIndex]
          [isLeft ? 'left' : 'right'];
    }
    return null;
  }

  Color? getLeftColor(int exerciseIndex, int pairIndex) {
    return _leftColors[exerciseIndex][pairIndex];
  }

  Color? getRightColor(int exerciseIndex, int pairIndex) {
    return _rightColors[exerciseIndex][pairIndex];
  }

  bool isOptionSelected(int exerciseIndex, String option, bool isLeft) {
    if (_matchingAnswers[exerciseIndex] == null) return false;
    return _matchingAnswers[exerciseIndex]!.any(
        (pair) => isLeft ? pair['left'] == option : pair['right'] == option);
  }

  // Navigation methods
  void goToExercise(int index) {
    if (index >= 0 && index < _exercises.length) {
      _currentExerciseIndex = index;
      print('Going to exercise: $_currentExerciseIndex'); // Debug print
      notifyListeners();
    }
  }

  void nextQuestion() {
    print('Current index before next: $_currentExerciseIndex'); // Debug print
    if (_currentExerciseIndex <
        (_exercises.isNotEmpty
            ? _exercises.length - 1
            : _reviewExercises.length - 1)) {
      _currentExerciseIndex++;
      print('Moving to next question: $_currentExerciseIndex'); // Debug print
      notifyListeners();
    }
  }

  void previousQuestion() {
    print(
        'Current index before previous: $_currentExerciseIndex'); // Debug print
    if (_currentExerciseIndex > 0) {
      _currentExerciseIndex--;
      print(
          'Moving to previous question: $_currentExerciseIndex'); // Debug print
      notifyListeners();
    }
  }

  // Progress tracking methods
  int getAnsweredCount() {
    return _answers.where((answer) => answer.isNotEmpty).length;
  }

  double getProgress() {
    return getAnsweredCount() / _exercises.length;
  }

  bool isExerciseCompleted(int index) {
    if (_exercises[index].choices is MatchingPair) {
      return isAllPairsMatched(index);
    }
    return _answers[index].isNotEmpty;
  }

  void _resetReviewState() {
    _reviewData = null;
    _reviewExercises = [];
  }

  // API methods
  Future<void> fetchExercises(String levelId) async {
    if (_isLoading) return; // Hindari multiple calls

    _isLoading = true;
    _currentExerciseIndex = 0;
    _resetReviewState();
    notifyListeners();

    // Reset shuffled pairs
    _shuffledRightPairsList = [];

    try {
      final token = await _userProvider.getValidToken();
      if (token == null) {
        throw Exception('No valid token found');
      }

      final data = await _repository.getExercises(levelId, token);
      _nameTopic = data['NAME_TOPIC'];
      _nameLevel = data['NAME_LEVEL'];
      final exercisesData = data['EXERCISES'];

      // Map exercises
      _exercises = exercisesData
          .map<ExerciseModel>((json) => ExerciseModel.fromJson(json))
          .toList();

      // Inisialisasi pengacakan untuk matching pairs
      initializeShuffledRightPairs(_exercises);

      // Inisialisasi jawaban
      _answers = List.generate(_exercises.length, (index) => '');
      initializeAnswers();
    } catch (e) {
      print('Error fetching exercises: $e');
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Di dalam ExerciseProvider class
  Future<void> fetchReviewExercises(String stdLearningId) async {
    _isLoading = true;
    _currentExerciseIndex = 0;
    notifyListeners();

    try {
      final token = await _userProvider.getValidToken();
      if (token == null) throw Exception('No valid token found');

      final response =
          await _repository.getStudentAnswers(stdLearningId, token);

      // Parse the response data
      final payload = response['payload'];
      _reviewData = ReviewExerciseModel.fromJson(payload);

      restoreShuffledRightPairs();

      // Sort the exercises based on the title number
      _reviewExercises = (_reviewData?.stdExercises ?? [])
        ..sort((a, b) {
          // Extract numbers from titles (e.g., "Soal 1" -> 1)
          int aNumber = int.tryParse(a.title.split(' ').last) ?? 0;
          int bNumber = int.tryParse(b.title.split(' ').last) ?? 0;
          return aNumber.compareTo(bNumber);
        });

      _nameTopic = _reviewData?.nameTopic ?? '';
      _nameLevel = _reviewData?.nameLevel ?? '';

      // Reset current index
      _currentExerciseIndex = 0;
    } catch (e) {
      print('Error fetching review exercises: $e');
      rethrow;
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  dynamic get currentExercise {
    if (_reviewExercises.isNotEmpty) {
      return _reviewExercises[_currentExerciseIndex];
    } else if (_exercises.isNotEmpty) {
      return _exercises[_currentExerciseIndex];
    }
    return null;
  }

  String getAnswerFormatted(ReviewExerciseDetail exercise) {
    switch (exercise.questionType) {
      case 'MCQ':
        if (exercise.multipleChoices != null) {
          final choice = exercise.answerStudent;
          final choices = exercise.multipleChoices!.first;
          switch (choice) {
            case 'A':
              return choices.optionA;
            case 'B':
              return choices.optionB;
            case 'C':
              return choices.optionC;
            case 'D':
              return choices.optionD;
            case 'E':
              return choices.optionE;
            default:
              return exercise.answerStudent;
          }
        }
        return exercise.answerStudent;
      case 'TFQ':
        return exercise.answerStudent == '1' ? 'True' : 'False';
      case 'MPQ':
        if (exercise.answerStudent.isEmpty) return '';
        return exercise.answerStudent.split(', ').map((pair) {
          final parts = pair.split('-');
          if (parts.length == 2) {
            return '${parts[0]} ➜ ${parts[1]}';
          }
          return pair;
        }).join('\n');
      default:
        return exercise.answerStudent;
    }
  }

  Future<Map<String, dynamic>> submitAnswersAndGetScore() async {
    // Simpan urutan acak sebelum submit
    saveShuffledRightPairs();
    try {
      if (_studentLearningId == null) {
        throw Exception('Student Learning ID is not set');
      }

      final token = await _userProvider.getValidToken();
      if (token == null) {
        throw Exception('No valid token found');
      }

      final answersToSubmit = _exercises.asMap().entries.where((entry) {
        final index = entry.key;
        return _answers[index].isNotEmpty;
      }).map((entry) {
        final index = entry.key;
        final exercise = entry.value;
        String formattedAnswer = _answers[index];
        if (exercise.choices is MultipleChoice) {
          formattedAnswer = formattedAnswer;
        } else if (exercise.choices is TrueFalse) {
          formattedAnswer = formattedAnswer.toLowerCase() == 'true' ? '1' : '0';
        }

        return {
          'ID_STUDENT_LEARNING': _studentLearningId!,
          'ID_ADMIN_EXERCISE': exercise.idAdminExercise,
          'ANSWER_STUDENT': formattedAnswer,
        };
      }).toList();

      if (answersToSubmit.isEmpty) {
        throw Exception(
            'No answers to submit. Please answer at least one question.');
      }

      print('Submitting answers to repository');
      final result = await _repository.submitAnswersAndGetScore(
          answersToSubmit, _studentLearningId!, token);

      print('Repository response: $result');

      return {
        'CURRENT_LEVEL_NAME': result['CURRENT_LEVEL_NAME'],
        'NEXT_LEARNING_NAME': result['NEXT_LEARNING_NAME'],
        'SCORE': result['SCORE'],
        'IS_PASS': result['IS_PASS'],
      };
    } catch (e) {
      print('Error in submitAnswersAndGetScore: $e');
      rethrow;
    }
  }

  Future<FeedbackModel> submitFeedback(String feedback) async {
    try {
      final token = await _userProvider.getValidToken();
      if (token == null) {
        throw Exception('No valid token found');
      }
      if (_studentLearningId == null) {
        throw Exception('Student Learning ID is not set');
      }
      print('Submitting feedback for stdLearningId: $_studentLearningId');
      final result = await _repository.submitFeedback(
          _studentLearningId!, feedback, token);
      print('Feedback submitted successfully');
      return result;
    } catch (e) {
      print('Error submitting feedback: $e');
      rethrow;
    }
  }

  bool hasAnsweredQuestions() {
    return _answers.any((answer) => answer.isNotEmpty);
  }

  bool hasUnansweredQuestions() {
    return _answers.any((answer) => answer.isEmpty);
  }

  // Other methods
  void setStudentLearningId(String id) {
    _studentLearningId = id;
    notifyListeners();
  }

  void updateFrom(ExerciseProvider? previous) {
    if (previous != null) {
      // Only copy non-review related state
      if (!previous._reviewExercises.isNotEmpty) {
        // If we're not coming from a review state
        _exercises = previous._exercises;
        _matchingAnswers = previous._matchingAnswers;
        _answers = previous._answers;
        _leftColors = previous._leftColors;
        _rightColors = previous._rightColors;
        _currentExerciseIndex = previous._currentExerciseIndex;
        _nameTopic = previous._nameTopic;
        _nameLevel = previous._nameLevel;
        _studentLearningId = previous._studentLearningId;
      } else {
        // If we are coming from a review state, reset everything
        _exercises = [];
        _matchingAnswers = {};
        _answers = [];
        _leftColors = [];
        _rightColors = [];
        _currentExerciseIndex = 0;
        _nameTopic = '';
        _nameLevel = '';
        _studentLearningId = previous._studentLearningId;
      }
      _isLoading = false;
    }
  }
}
