import 'dart:io';
import 'package:english_learning/core/services/repositories/user_repository.dart';
import 'package:flutter/material.dart';
import 'package:jwt_decoder/jwt_decoder.dart';

class UserProvider with ChangeNotifier {
  final UserRepository _userRepository = UserRepository();
  bool _isLoggedIn = false;
  String? _jwtToken;
  Map<String, dynamic>? _userData;
  File? _selectedImage;
  bool _isLoading = false;
  int? _errorCode;

  bool get isLoading => _isLoading;
  bool get isLoggedIn => _isLoggedIn;
  String? get jwtToken => _jwtToken;
  Map<String, dynamic>? get userData => _userData;
  File? get selectedImage => _selectedImage;
  int? get errorCode => _errorCode;

  UserProvider() {
    _loadLoginStatus();
  }

  void setLoading(bool value) {
    _isLoading = value;
    notifyListeners();
  }

  Future<void> _loadLoginStatus() async {
    try {
      _jwtToken = await _userRepository.getToken();
      if (_jwtToken != null) {
        if (JwtDecoder.isExpired(_jwtToken!)) {
          await logout();
        } else {
          _isLoggedIn = true;
          await _loadUserData();
        }
      }
    } catch (e) {
      print('Error loading login status: $e');
    }
    notifyListeners();
  }

  Future<void> _loadUserData() async {
    _userData = await _userRepository.getUserData();
    if (_userData == null) {
      await refreshUserData();
    }
  }

  Future<void> refreshUserData() async {
    try {
      if (_jwtToken != null) {
        final response = await _userRepository.getMe(_jwtToken!);
        if (response.statusCode == 200) {
          _userData = response.data['payload'];
          // Save all user data securely
          await _userRepository.saveUserData(_userData!);
          notifyListeners();
        }
      }
    } catch (e) {
      print('Error refreshing user data: $e');
    }
  }

  Future<bool> login({required String email, required String password}) async {
    setLoading(true);
    _errorCode = null;
    try {
      final response = await _userRepository.loginUser({
        'EMAIL': email,
        'PASSWORD': password,
      });

      _errorCode = response.statusCode;

      if (response.statusCode == 200 &&
          response.data['payload']['TOKEN'] != null) {
        String token = response.data['payload']['TOKEN'];
        String refreshToken = response.data['payload']['REFRESH_TOKEN'];
        if (token.startsWith('Bearer ')) {
          token = token.substring(7);
        }
        _jwtToken = token;
        await _userRepository.saveToken(_jwtToken!);
        await _userRepository.saveRefreshToken(refreshToken);
        _isLoggedIn = true;
        await refreshUserData();
        return true;
      } else if (response.statusCode == 403) {
        // Khusus untuk error 403 (user belum divalidasi)
        print('User is not validated: ${response.data['message']}');
        return false;
      }

      return false;
    } catch (e) {
      print('Login error: $e');
      return false;
    } finally {
      setLoading(false);
    }
  }

  Future<bool> register({
    required String name,
    required String email,
    required String nisn,
    required String password,
    required String confirmPassword,
  }) async {
    try {
      final response = await _userRepository.registerUser({
        "NAME_USERS": name,
        "EMAIL": email,
        "NISN": nisn,
        "PASSWORD": password,
        "CONFIRM_PASSWORD": confirmPassword,
      });

      if (response.statusCode == 200) {
        return true;
      }
      return false;
    } catch (e) {
      print('Registration error: $e');
      return false;
    }
  }

  Future<bool> logout() async {
    try {
      final response = await _userRepository.logoutUser();

      if (response.statusCode == 200) {
        _isLoggedIn = false;
        _jwtToken = null;
        _userData = null;
        await _userRepository.deleteToken();
        await _userRepository.deleteRefreshToken();
        await _userRepository.deleteUserData();
        notifyListeners();
        return true;
      }
      return false;
    } catch (e) {
      print('Logout error: $e');
      _isLoggedIn = false;
      _jwtToken = null;
      _userData = null;
      await _userRepository.deleteToken();
      await _userRepository.deleteRefreshToken();
      await _userRepository.deleteUserData();
      notifyListeners();
      return false;
    }
  }

  Future<bool> forgotPassword({required String email}) async {
    try {
      final response = await _userRepository.forgotPassword(email);

      if (response.statusCode == 200) {
        print("Password reset email sent successfully!");
        return true;
      } else if (response.statusCode == 404) {
        print("Email is not registered!");
        return false;
      }
      return false;
    } catch (e) {
      print('Forgot Password error: $e');
      return false;
    }
  }

  Future<bool> refreshToken() async {
    try {
      final refreshToken = await _userRepository.getRefreshToken();
      if (refreshToken == null) return false;

      final response =
          await _userRepository.dioClient.refreshAccessToken(refreshToken);

      if (response.statusCode == 200) {
        String newToken = response.data['payload']['TOKEN'];
        String newRefreshToken = response.data['payload']['REFRESH_TOKEN'];

        if (newToken.startsWith('Bearer ')) {
          newToken = newToken.substring(7);
        }

        _jwtToken = newToken;
        await _userRepository.saveToken(_jwtToken!);
        await _userRepository.saveRefreshToken(newRefreshToken);

        return true;
      }
      return false;
    } catch (e) {
      print('Error refreshing token: $e');
      return false;
    }
  }

  Future<bool> isTokenValid() async {
    if (_jwtToken == null) return false;
    if (JwtDecoder.isExpired(_jwtToken!)) {
      return await refreshToken();
    }
    return true;
  }

  Future<String?> getValidToken() async {
    try {
      if (await isTokenValid()) {
        return _jwtToken;
      }
      return null;
    } catch (e) {
      print('Error in getValidToken: $e');
      return null;
    }
  }

  Future<void> updateUserProfile(Map<String, dynamic> updatedData) async {
    try {
      final token = await getValidToken();
      final userId = _userData?['ID'];
      if (token != null && userId != null) {
        final response = await _userRepository.updateUserProfile(
          userId,
          updatedData,
          token,
          imageFile: _selectedImage,
        );
        if (response.statusCode == 200) {
          _userData = response.data['payload'];
          // Save updated user data securely
          await _userRepository.saveUserData(_userData!);
          _selectedImage =
              null; // Reset the selected image after successful update
          notifyListeners();
        }
      }
    } catch (e) {
      print('Error updating user profile: $e');
      rethrow;
    }
  }

  Future<bool> updatePassword({
    required String oldPassword,
    required String newPassword,
    required String confirmPassword,
  }) async {
    try {
      final token = await getValidToken();
      final userId = _userData?['ID'];
      if (token != null && userId != null) {
        final response = await _userRepository.updatePassword(
          userId,
          oldPassword,
          newPassword,
          confirmPassword,
          token,
        );
        if (response.statusCode == 200) {
          print("Password updated successfully!");
          return true;
        }
      }
      return false;
    } catch (e) {
      print('Error updating password: $e');
      return false;
    }
  }

  Future<bool> reportIssue(String report) async {
    try {
      final token = await getValidToken();
      if (token != null) {
        final response = await _userRepository.reportIssue(report, token);
        if (response.statusCode == 201) {
          print("Issue reported successfully!");
          return true;
        }
      }
      return false;
    } catch (e) {
      print('Error reporting issue: $e');
      return false;
    }
  }

  String? getUserName() {
    return _userData?['NAME_USERS'];
  }

  void setSelectedImage(File? image) {
    _selectedImage = image;
    notifyListeners();
  }
}
