import 'package:auth/src/features/recover_password/domain/use_cases/recover_password_use_case.dart';
import 'package:auth/src/features/recover_password/presentation/state/recover_password_view_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../providers/recover_password_provider.dart';

final recoverPasswordViewModelProvider =
NotifierProvider.autoDispose<RecoverPasswordViewModel, RecoverPasswordViewState>(
  RecoverPasswordViewModel.new,
);

class RecoverPasswordViewModel extends Notifier<RecoverPasswordViewState> {
  late final RecoverPasswordUseCase _recoverPasswordUseCase;
  late final TextEditingController phoneNumberController;
  late final TextEditingController emailController;
  late final TextEditingController passwordController;
  late final TextEditingController repeatedPasswordController;
  late final TextEditingController newPhoneNumberController;

  @override
  RecoverPasswordViewState build() {
    _recoverPasswordUseCase = ref.read(recoverPasswordUseCaseProvider);

    phoneNumberController = TextEditingController();
    phoneNumberController.addListener(_onPhoneNumberChanged);

    emailController = TextEditingController();
    emailController.addListener(_onEmailChanged);

    passwordController = TextEditingController();
    passwordController.addListener(_onPasswordChanged);

    repeatedPasswordController = TextEditingController();
    repeatedPasswordController.addListener(_onRepeatedPasswordChanged);

    newPhoneNumberController = TextEditingController();
    newPhoneNumberController.addListener(_onNewPhoneNumberChanged);

    ref.onDispose(disposeControllers);

    return const RecoverPasswordViewState();
  }

  void _onPhoneNumberChanged() {
    final String raw = phoneNumberController.text;
    state = state.copyWith(
      phoneNumber: raw,
      errorMessage: '',
      recoveryRequested: false,
    );
  }

  void _onNewPhoneNumberChanged() {
    final String raw = newPhoneNumberController.text;
    state = state.copyWith(
      newPhoneNumber: raw,
      errorMessage: '',
      recoveryRequested: false,
    );
  }

  void _onEmailChanged() {
    final String raw = emailController.text;
    state = state.copyWith(
      email: raw,
      errorMessage: '',
      recoveryRequested: false,
    );
  }

  void _onPasswordChanged() {
    final String raw = passwordController.text;
    final bool equalPasswords = raw == repeatedPasswordController.text;

    final bool minCheck = raw.length >= 8;
    final bool capitalCheck = RegExp(r'[A-Z]').hasMatch(raw);
    final bool numberCheck = RegExp(r'[0-9]').hasMatch(raw);
    final bool specialCheck = RegExp(r'[^A-Za-z0-9]').hasMatch(raw);

    final Map<String, bool> security = {
      'min': minCheck,
      'capital': capitalCheck,
      'number': numberCheck,
      'special': specialCheck,
    };

    state = state.copyWith(
      password: raw,
      errorMessage: '',
      equalPasswords: equalPasswords,
      securityChecks: security,
    );
  }

  void _onRepeatedPasswordChanged() {
    final String raw = repeatedPasswordController.text;
    final bool equalPasswords = raw == passwordController.text;
    state = state.copyWith(
      repeatedPassword: raw,
      errorMessage: '',
      equalPasswords: equalPasswords,
    );
  }

  void updateDialCode(String dialCode) {
    state = state.copyWith(
      dialCode: dialCode,
      errorMessage: '',
    );
  }

  void updateNewDialCode(String dialCode) {
    state = state.copyWith(
      newDialCode: dialCode,
      errorMessage: '',
    );
  }

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

  Future<void> requestRecovery() async {
    final trimmedNumber = state.phoneNumber.trim();
    final email = state.email.trim();

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

    if (email.isNotEmpty) {
      await requestEmail();
    } else if (trimmedNumber.isNotEmpty) {
      await requestSms();
    } else {
      state = state.copyWith(
        isLoading: false,
        errorMessage: 'errorMessageContactIsEmpty',
      );
      return;
    }
  }

  Future<void> requestEmail() async {
    final email = state.email.trim();

    try {
      final String token = await _recoverPasswordUseCase.requestEmail(email: email);
      if (!ref.mounted) return;

      state = state.copyWith(
        isLoading: false,
        errorMessage: '',
        recoveryRequested: true,
        token: token,
        recoveryFormat: 'email',
      );
    } catch (e) {
      if (!ref.mounted) return;

      state = state.copyWith(
        isLoading: false,
        errorMessage: e.toString(),
        recoveryRequested: false,
        passwordChanged: false,
      );
    }
  }

  Future<void> requestSms() async {
    final trimmedNumber = state.phoneNumber.trim();

    final fullPhone = '${state.dialCode}$trimmedNumber';

    try {
      final String token = await _recoverPasswordUseCase.requestSms(phone: fullPhone);
      if (!ref.mounted) return;

      state = state.copyWith(
        isLoading: false,
        errorMessage: '',
        recoveryRequested: true,
        token: token,
        recoveryFormat: 'sms'
      );
    } catch (e) {
      if (!ref.mounted) return;

      state = state.copyWith(
        isLoading: false,
        errorMessage: e.toString(),
        recoveryRequested: false,
        passwordChanged: false,
      );
    }
  }

  Future<void> recoverPassword() async {
    //final String fullPhone = state.newDialCode + state.newPhoneNumber;
    final String password = state.password;

    if (!state.equalPasswords) {
      state = state.copyWith(
        errorMessage: 'errorMessageUnequalPasswords',
        passwordChanged: false,
      );
      return;
    }

    if (!state.securityChecks['min']!) {
      state = state.copyWith(
        errorMessage: 'errorMessagePasswordTooShort',
        passwordChanged: false,
      );
      return;
    }

    if (!state.securityChecks['capital']!) {
      state = state.copyWith(
        errorMessage: 'errorMessagePasswordNoCapitals',
        passwordChanged: false,
      );
      return;
    }

    if (!state.securityChecks['number']!) {
      state = state.copyWith(
        errorMessage: 'errorMessagePasswordNoNumbers',
        passwordChanged: false,
      );
      return;
    }

    if (!state.securityChecks['special']!) {
      state = state.copyWith(
        errorMessage: 'errorMessagePasswordNoSpecialChars',
        passwordChanged: false,
      );
      return;
    }

    state = state.copyWith(
      isLoading: true,
      passwordChanged: false,
    );
    try {
      await _recoverPasswordUseCase.recoverPassword(
          newPassword: password, token: state.token);
      state = state.copyWith(
        isLoading: false,
        passwordChanged: true,
      );
    } catch (error) {
      state = state.copyWith(
        errorMessage: error.toString(),
        isLoading: false,
        passwordChanged: false,
      );
    }
  }

  void disposeControllers() {
    phoneNumberController.removeListener(_onPhoneNumberChanged);
    phoneNumberController.dispose();
    emailController.removeListener(_onPhoneNumberChanged);
    emailController.dispose();
    passwordController.removeListener(_onPasswordChanged);
    passwordController.dispose();
    repeatedPasswordController.removeListener(_onRepeatedPasswordChanged);
    repeatedPasswordController.dispose();
    newPhoneNumberController.removeListener(_onNewPhoneNumberChanged);
    newPhoneNumberController.dispose();
  }
}