import 'package:auth/src/features/login/domain/login_use_case.dart';
import 'package:auth/src/features/login/domain/two_factor_use_case.dart';
import 'package:auth/src/features/login/presentation/providers/login_provider.dart';
import 'package:auth/src/features/login/presentation/providers/two_factor_provider.dart';
import 'package:auth/src/features/login/presentation/state/login_view_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sf_localizations/sf_localizations.dart';

final loginViewModelProvider =
    NotifierProvider.autoDispose<LoginViewModel, LoginViewState>(
      LoginViewModel.new,
    );

class LoginViewModel extends Notifier<LoginViewState> {
  late final LoginUseCase _loginUseCase;
  late final TwoFactorUseCase _twoFactorUseCase;

  late final TextEditingController emailController;
  late final TextEditingController passwordController;

  late final TextEditingController otpController;

  static final RegExp _emailRegex = RegExp(
    r'^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$',
    caseSensitive: false,
  );

  @override
  LoginViewState build() {
    _loginUseCase = ref.read(loginUseCaseProvider);
    _twoFactorUseCase = ref.read(twoFactorUseCaseProvider);

    emailController = TextEditingController();
    passwordController = TextEditingController();
    otpController = TextEditingController();

    emailController.addListener(_onEmailChanged);
    passwordController.addListener(_onPasswordChanged);
    otpController.addListener(_onOtpChanged);

    ref.onDispose(disposeControllers);

    return const LoginViewState();
  }

  void _onEmailChanged() {
    final text = emailController.text;
    if (text == state.email) return;

    state = state.copyWith(email: text, errorMessage: '');

    if (state.showErrors) {
      state = state.copyWith(emailError: _emailErrorFor(text));
    }
  }

  void _onPasswordChanged() {
    final text = passwordController.text;
    if (text == state.password) return;

    state = state.copyWith(password: text, errorMessage: '');

    if (state.showErrors) {
      state = state.copyWith(passwordError: _passwordErrorFor(text));
    }
  }

  void togglePasswordVisible() {
    state = state.copyWith(passwordVisible: !state.passwordVisible);
  }

  bool _isValidEmail(String email) => _emailRegex.hasMatch(email);

  String _emailErrorFor(String value) {
    final email = value.trim();
    if (email.isEmpty) return I18n.errorEmailRequired;
    if (!_isValidEmail(email)) return I18n.errorEmailInvalid;
    return '';
  }

  String _passwordErrorFor(String value) {
    final password = value.trim();
    if (password.isEmpty) return I18n.errorPasswordRequired;
    if (password.length < 6) return I18n.errorPasswordMinLength;
    return '';
  }

  bool _validateForm() {
    final emailError = _emailErrorFor(state.email);
    final passwordError = _passwordErrorFor(state.password);

    state = state.copyWith(
      showErrors: true,
      emailError: emailError,
      passwordError: passwordError,
      errorMessage: '',
    );

    return emailError.isEmpty && passwordError.isEmpty;
  }

  Future<String?> login() async {
    if (!_validateForm()) return null;

    final email = state.email.trim();
    final password = state.password.trim();

    state = state.copyWith(isLoading: true, errorMessage: '');

    try {
      final String token = await _loginUseCase.login(
        email: email,
        password: password,
      );

      if (!ref.mounted) return null;

      state = state.copyWith(isLoading: false);
      return token;
    } catch (e) {
      if (!ref.mounted) return null;

      state = state.copyWith(isLoading: false, errorMessage: e.toString());
      return null;
    }
  }

  void prepareTwoFactor() {
    otpController.text = '';
    state = state.copyWith(otpCode: '', otpError: '', isOtpLoading: false);
  }

  void _onOtpChanged() {
    final raw = otpController.text;
    if (raw == state.otpCode) return;

    state = state.copyWith(otpCode: raw, otpError: '');

    if (state.showErrors) {
      state = state.copyWith(otpError: _otpErrorFor(raw));
    }
  }

  void setOtpCode(String code) {
    state = state.copyWith(otpCode: code, otpError: '');
  }

  String _otpErrorFor(String value) {
    final code = value.trim();
    if (code.isEmpty) return I18n.errorTwoFactorCodeRequired;
    if (code.length != 6) return I18n.errorTwoFactorCodeInvalidLength;
    return '';
  }

  bool _validateOtp() {
    final otpError = _otpErrorFor(state.otpCode);

    state = state.copyWith(
      showErrors: true,
      otpError: otpError,
      errorMessage: '',
    );

    return otpError.isEmpty;
  }

  Future<bool> twoFactor({required String token}) async {
    if (!_validateOtp()) return false;

    final code = state.otpCode.trim();

    state = state.copyWith(isOtpLoading: true, otpError: '', errorMessage: '');

    try {
      await _twoFactorUseCase.twoFactor(token: token, code: code);

      if (!ref.mounted) return false;

      state = state.copyWith(isOtpLoading: false);
      return true;
    } catch (e) {
      if (!ref.mounted) return false;

      state = state.copyWith(
        isOtpLoading: false,
        otpError: I18n.errorTwoFactorCodeInvalid,
      );
      return false;
    }
  }

  void disposeControllers() {
    emailController.removeListener(_onEmailChanged);
    passwordController.removeListener(_onPasswordChanged);
    otpController.removeListener(_onOtpChanged);

    emailController.dispose();
    passwordController.dispose();
    otpController.dispose();
  }
}
