import 'package:flutter/material.dart';
import 'package:tm_app/data/services/model/customer/customer.dart';
import 'package:tm_app/data/services/model/forgot_password_response/forgot_password_response_model.dart';
import 'package:tm_app/data/services/model/verify_otp_response/verify_otp_response_model.dart';

import '../core/utils/result.dart';
import '../data/repositories/auth_repository.dart';
import '../data/services/model/login_response/login_response_model.dart';
import '../data/services/model/logout_response/logout_response.dart';
import '../data/services/model/reset_password_response/reset_password_response.dart';

class AuthViewModel with ChangeNotifier {
  final AuthRepository _authRepository;

  AuthViewModel({required AuthRepository authRepository})
    : _authRepository = authRepository {
    usernameController.addListener(_onTextChanged);
    passwordController.addListener(_onTextChanged);
    emailController.addListener(_onTextChanged);
    otpController.addListener(_onTextChanged);
    newPasswordController.addListener(_onTextChanged);
  }

  final TextEditingController usernameController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();
  final TextEditingController emailController = TextEditingController();
  final TextEditingController newPasswordController = TextEditingController();
  final TextEditingController otpController = TextEditingController();

  final FocusNode usernameFocus = FocusNode();
  final FocusNode passwordFocus = FocusNode();
  final FocusNode emailFocus = FocusNode();
  final FocusNode newPasswordFocus = FocusNode();
  final FocusNode otpFocus = FocusNode();

  bool _obscurePassword = true;
  bool get obscurePassword => _obscurePassword;

  bool _obscureForgotPassword = true;
  bool get obscureForgotPassword => _obscureForgotPassword;

  bool get isLoginEnabled =>
      usernameController.text.isNotEmpty && passwordController.text.isNotEmpty;

  // Auth state
  bool _isLoading = false;
  bool _isLoggedIn = false;
  bool _isResetPasswordLoading = false;
  String? _errorMessage;
  String? _resetPasswordErrorMessage;
  bool _resetPasswordSuccess = false;
  Customer? _loggedInUser;
  String? successMessage;
  String? _successMessageOtp;
  String? _forgotPasswordMessage;
  bool _isLoadingForgot = false;
  bool _isLoadingOtp = false;
  String? _errorMessageForget;
  String? _errorMessageOtp;
  bool _verifyOtpSuccess = false;

  bool get isLoading => _isLoading;
  bool get isLoggedIn => _isLoggedIn;
  bool get isLoadingForgot => _isLoadingForgot;
  bool get isLoadingOtp => _isLoadingOtp;
  bool get isResetPasswordLoading => _isResetPasswordLoading;
  String? get errorMessage => _errorMessage;
  String? get errorMessageForget => _errorMessageForget;
  String? get resetPasswordErrorMessage => _resetPasswordErrorMessage;
  String? get errorMessageOtp => _errorMessageOtp;
  String? get successMessageOtp => _successMessageOtp;
  bool get verifyOtpSuccess => _verifyOtpSuccess;
  Customer? get loggedInUser => _loggedInUser;
  String? get forgotPasswordMessage => _forgotPasswordMessage;
  String? resetToken;
  bool get resetPasswordSuccess => _resetPasswordSuccess;

  void togglePasswordVisibility() {
    _obscurePassword = !_obscurePassword;
    notifyListeners();
  }

  void toggleForgotPasswordVisibility() {
    _obscureForgotPassword = !_obscureForgotPassword;
    notifyListeners();
  }

  bool get isEmailValid {
    final email = emailController.text.trim();
    final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
    return emailRegex.hasMatch(email);
  }

  bool get isOtpValid {
    final otp = otpController.text.trim();
    return otp.length == 6;
  }

  bool get canSubmitOtpPage {
    return isOtpValid;
  }

  bool get isNewPasswordValid {
    final password = newPasswordController.text.trim();

    final hasMinLength = password.length >= 5;
    final hasUppercase = RegExp(r'[A-Z]').hasMatch(password);
    final hasLowercase = RegExp(r'[a-z]').hasMatch(password);
    final hasSpecialChar = RegExp(r'[!@#\$%&\*\^]').hasMatch(password);

    return hasMinLength && hasUppercase && hasLowercase && hasSpecialChar;
  }

  void _onTextChanged() {
    notifyListeners();
  }

  Future<void> login() async {
    _isLoading = true;
    _errorMessage = null;
    notifyListeners();

    await localLogout();

    final result = await _authRepository.login(
      username: usernameController.text.trim(),
      password: passwordController.text.trim(),
    );

    switch (result) {
      case Ok<LoginResponseModel>():
        _loggedInUser = result.value.data.customer;
        usernameController.clear();
        passwordController.clear();
        break;
      case Error<LoginResponseModel>():
        _errorMessage = result.error.toString();
        break;
    }

    _isLoading = false;
    notifyListeners();

    // reset error after notify
    _errorMessage = null;
    notifyListeners();
  }

  Future<void> localLogout() async {
    await _authRepository.localLogout();
    _loggedInUser = null;
    notifyListeners();
  }

  Future<void> logout() async {
    _errorMessage = null;
    notifyListeners();

    final result = await _authRepository.logout();

    switch (result) {
      case Ok<LogoutResponse>():
        localLogout();
        break;
      case Error<LogoutResponse>():
        _errorMessage = result.error.toString();
        break;
    }

    notifyListeners();

    _errorMessage = null;
    notifyListeners();
  }

  Future<void> forgotPassword(BuildContext context) async {
    _isLoadingForgot = true;
    _errorMessageForget = null;
    successMessage = null;
    notifyListeners();

    final result = await _authRepository.forgotPassword(
      email: emailController.text.trim(),
    );

    switch (result) {
      case Ok<ForgotPasswordResponseModel>():
        _isLoadingForgot = false;
        successMessage = result.value.message;

        notifyListeners();

        break;

      case Error<ForgotPasswordResponseModel>():
        _isLoadingForgot = false;
        _errorMessageForget = result.error.toString();
        notifyListeners();

        Future.microtask(() {
          _errorMessageForget = null;
        });
        break;
    }
  }

  void clearMessages() {
    successMessage = null;
    _errorMessage = null;
    notifyListeners();
  }

  Future<void> verifyOtp(BuildContext context) async {
    _isLoadingOtp = true;
    _errorMessageOtp = null;
    _verifyOtpSuccess = false;
    notifyListeners();

    final result = await _authRepository.verifyOtp(
      code: otpController.text.trim(),
      email: emailController.text.trim(),
    );

    switch (result) {
      case Ok<VerifyOtpResponseModel>():
        _isLoadingOtp = false;
        resetToken = result.value.data.token;
        _successMessageOtp = result.value.message;
        _verifyOtpSuccess = true;
        notifyListeners();

        break;

      case Error<VerifyOtpResponseModel>():
        _isLoadingOtp = false;
        _errorMessageOtp = result.error.toString();
        _verifyOtpSuccess = false;
        notifyListeners();
        break;
    }

    _errorMessageOtp = null;
    _successMessageOtp = null;
    notifyListeners();
  }

  void clearOtpFlow() {
    _errorMessageOtp = null;
    _successMessageOtp = null;
    _isLoadingOtp = false;
    _verifyOtpSuccess = false;
    // Intentionally do not clear resetToken
    otpController.clear();
    notifyListeners();
  }

  Future<void> resetPassword() async {
    _isResetPasswordLoading = true;
    _resetPasswordErrorMessage = null;
    _resetPasswordSuccess = false;
    notifyListeners();
    if (resetToken != null) {
      final result = await _authRepository.resetPassword(
        newPassword: newPasswordController.text.trim(),
        token: resetToken!,
      );
      switch (result) {
        case Ok<ResetPasswordResponse>():
          _resetPasswordSuccess = true;
          break;
        case Error<ResetPasswordResponse>():
          _resetPasswordErrorMessage = result.error.toString();
          _resetPasswordSuccess = false;
          break;
      }
      _isResetPasswordLoading = false;
      notifyListeners();
      _resetPasswordErrorMessage = null;
      notifyListeners();
    } else {
      _resetPasswordErrorMessage = 'Reset token is required';
      _isResetPasswordLoading = false;
      notifyListeners();
    }
  }

  Future<void> checkIsLoggedIn() async {
    final result = await _authRepository.checkIsLoggedIn();

    if (result is Ok<bool>) {
      if (result.value) {
        _isLoggedIn = result.value;
      } else {
        _isLoggedIn = false;
      }
    } else {
      _isLoggedIn = false;
    }
    notifyListeners();
  }

  void clearResetPasswordSuccess() {
    _resetPasswordSuccess = false;

    notifyListeners();
  }

  void clearResetFlow() {
    _resetPasswordErrorMessage = null;
    _resetPasswordSuccess = false;
    _isResetPasswordLoading = false;
    // Intentionally do not clear resetToken
    newPasswordController.clear();
    notifyListeners();
  }

  @override
  void dispose() {
    usernameController.dispose();
    passwordController.dispose();
    emailController.dispose();
    newPasswordController.dispose();
    otpController.dispose();

    usernameFocus.dispose();
    passwordFocus.dispose();
    emailFocus.dispose();
    newPasswordFocus.dispose();
    otpFocus.dispose();

    super.dispose();
  }
}
