import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:syncrow_app/features/auth/model/login_with_email_model.dart';
import 'package:syncrow_app/features/auth/model/signup_model.dart';
import 'package:syncrow_app/features/auth/model/token.dart';
import 'package:syncrow_app/features/auth/model/user_model.dart';
import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/services/api/authentication_api.dart';
import 'package:syncrow_app/utils/helpers/shared_preferences_helper.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
part 'auth_state.dart';

class AuthCubit extends Cubit<AuthState> {
  AuthCubit() : super(AuthInitial());
  static AuthCubit get(context) => BlocProvider.of(context);

  final TextEditingController emailController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();

  String fullName = '';
  String email = '';
  String forgetPasswordEmail = '';
  String signUpPassword = '';
  String newPassword = '';
  String maskedEmail = '';
  String otpCode = '';
  final loginFormKey = GlobalKey<FormState>();
  final signUpFormKey = GlobalKey<FormState>();
  final checkEmailFormKey = GlobalKey<FormState>();
  final createNewPasswordKey = GlobalKey<FormState>();

  bool isPasswordVisible = false;
  bool showValidationMessage = false;

  void changePasswordVisibility() {
    isPasswordVisible = !isPasswordVisible;
    emit(AuthPasswordVisibilityChanged());
  }

  bool agreeToTerms = false;

  void changeAgreeToTerms() {
    agreeToTerms = !agreeToTerms;
    emit(AuthAgreeToTermsChanged());
  }

  static UserModel? user;

  static Token token = Token.emptyConstructor();

  setOtpCode(String value) {
    otpCode = value;
  }

/////////////////////////////////////VALIDATORS/////////////////////////////////////
  String? passwordValidator(String? value) {
    List<String> errors = [];

    if (value == null || value.isEmpty) {
      errors.add("Please enter your password");
    }

    if (value != null && value.length < 8) {
      errors.add('Password must be at least 8 characters long');
    }

    if (value != null && !RegExp(r'[a-z]').hasMatch(value)) {
      errors.add('Password must contain at least one lowercase letter');
    }

    if (value != null && !RegExp(r'[A-Z]').hasMatch(value)) {
      errors.add('Password must contain at least one uppercase letter');
    }

    if (value != null && !RegExp(r'\d').hasMatch(value)) {
      errors.add('Password must contain at least one number');
    }

    if (value != null &&
        !RegExp(r'[!"#$%&()*+,-./:;<=>?@[\]^_`{|}~]').hasMatch(value)) {
      errors.add('Password must contain at least one special character');
    }

    if (errors.isNotEmpty) {
      return errors
          .join('\n'); // Join the errors with new lines to show all at once
    }

    return null; // No errors
  }

  String? fullNameValidator(String? value) {
    if (value == null) return 'Full name is required';

    final withoutExtraSpaces = value.replaceAll(RegExp(r"\s+"), ' ').trim();

    if (withoutExtraSpaces.length < 2 || withoutExtraSpaces.length > 30) {
      return 'Full name must be between 2 and 30 characters long';
    }

    // Test if it contains anything but alphanumeric spaces and single quote

    if (RegExp(r"/[^ a-zA-Z0-9-\']/").hasMatch(withoutExtraSpaces)) {
      return 'Only alphanumeric characters, space, dash and single quote are allowed';
    }

    final parts = withoutExtraSpaces.split(' ');

    if (parts.length < 2) return 'Full name must contain first and last names';

    if (parts.length > 3) return 'Full name can at most contain 3 parts';

    if (parts.any((part) => part.length < 2 || part.length > 30)) {
      return 'Full name parts must be between 2 and 30 characters long';
    }
    return null;
  }

  String? reEnterPasswordCheck(String? value) {
    passwordValidator(value);
    if (signUpPassword == value) {
      return null;
    } else {
      return 'Passwords do not match';
    }
  }

  String? reEnterPasswordCheckForgetPass(String? value) {
    passwordValidator(value);
    if (newPassword == value) {
      return null;
    } else {
      return 'Passwords do not match';
    }
  }

  String? emailAddressValidator(String? value) {
    if (value != null && value.isNotEmpty && value != "") {
      if (checkValidityOfEmail(value)) {
        return null;
      } else {
        return 'Please enter a valid email';
      }
    } else {
      return 'Email address is required';
    }
  }

  bool checkValidityOfEmail(String? email) {
    if (email != null) {
      return RegExp(
              r"^[a-zA-Z0-9]+([.!#$%&'*+/=?^_`{|}~-]?[a-zA-Z0-9]+)*@[a-zA-Z0-9]+([.-]?[a-zA-Z0-9]+)*\.[a-zA-Z0-9]{2,}$")
          .hasMatch(email);
    } else {
      return false;
    }
  }

  // Function to mask the email
  String maskEmail(String email) {
    final emailParts = email.split('@');
    if (emailParts.length != 2) return email;

    final localPart = emailParts[0];
    final domainPart = emailParts[1];

    if (localPart.length < 3) return email;

    final start = localPart.substring(0, 2);
    final end = localPart.substring(localPart.length - 1);

    final maskedLocalPart = '$start******$end';
    return '$maskedLocalPart@$domainPart';
  }

/////////////////////////////////////API CALLS/////////////////////////////////////
  login() async {
    emit(AuthLoginLoading());
    try {
      if (emailController.text.isEmpty || passwordController.text.isEmpty) {
        CustomSnackBar.displaySnackBar('Please enter your credentials');
        emit(AuthLoginError(message: 'Something went wrong'));
        return;
      }

      token = await AuthenticationAPI.loginWithEmail(
        model: LoginWithEmailModel(
          email: emailController.text.toLowerCase(),
          password: passwordController.text,
        ),
      );
    } catch (failure) {
      emit(AuthLoginError(message: failure.toString()));
      return;
    }
    if (token.accessTokenIsNotEmpty) {
      debugPrint('token: ${token.accessToken}');
      FlutterSecureStorage storage = const FlutterSecureStorage();
      await storage.write(
          key: Token.loginAccessTokenKey, value: token.accessToken);
      const FlutterSecureStorage().write(
          key: UserModel.userUuidKey,
          value: Token.decodeToken(token.accessToken)['uuid'].toString());

      user = UserModel.fromToken(token);
      emailController.clear();
      passwordController.clear();
      emit(AuthLoginSuccess());
    } else {
      emit(AuthLoginError(message: 'Something went wrong'));
    }
  }

  signUp() async {
    emit(AuthLoginLoading());
    final response;

    final clientId = dotenv.env['CLIENT_ID'] ?? '';
    final clientSecret = dotenv.env['CLIENT_SECRET'] ?? '';

    try {
      List<String> userFullName = fullName.split(' ');

      final clientToken = await AuthenticationAPI.fetchClientToken(
        clientId: clientId,
        clientSecret: clientSecret,
      );

      final accessToken = clientToken['accessToken'];

      response = await AuthenticationAPI.signUp(
        accessToken: accessToken,
        model: SignUpModel(
            hasAcceptedAppAgreement: true,
            email: email.toLowerCase(),
            password: signUpPassword,
            firstName: userFullName[0],
            lastName: userFullName[1]),
      );
    } catch (failure) {
      emit(AuthLoginError(message: failure.toString()));
      return;
    }
    if (response) {
      maskedEmail = maskEmail(email);
      await sendOtp();
    } else {
      emit(AuthLoginError(message: 'Something went wrong'));
    }
  }

  sendOtp({bool? isforget}) async {
    try {
      emit(AuthLoading());
      await AuthenticationAPI.sendOtp(body: {
        'email': email,
        'type': isforget == true ? 'PASSWORD' : 'VERIFICATION'
      });
      emit(AuthSignUpSuccess());
    } catch (_) {
      emit(AuthErrorStatusWithoutMsg());

      // emit(AuthLoginError(message: 'Something went wrong'));
    }
  }

  Future<bool> reSendOtp({bool? forget}) async {
    try {
      emit(ResendOtpLoading());
      await AuthenticationAPI.sendOtp(body: {
        'email': email,
        'type': forget == true ? 'PASSWORD' : 'VERIFICATION'
      });
      emit(ResendOtpSuccess());
      return true;
    } catch (_) {
      emit(AuthErrorStatusWithoutMsg());

      // emit(AuthLoginError(message: 'Something went wrong'));
      return false;
    }
  }

  verifyOtp(bool isForgotPass) async {
    if (otpCode.length != 6) {
      return;
    }
    emit(AuthOtpLoading());
    try {
      final response = await AuthenticationAPI.verifyPassCode(body: {
        'email': email,
        'type': isForgotPass == true ? 'PASSWORD' : 'VERIFICATION',
        'otpCode': otpCode
      });
      if (response['statusCode'] == 200) {
        if (!isForgotPass) {
          emailController.text = email;
          passwordController.text = signUpPassword;
          await login();
        }
        emit(AuthOtpSuccess());
      }
      // else {
      //  emit(AuthLoginError(message: 'Something went wrong'));
      // }
    } catch (failure) {
      emit(AuthErrorStatusWithoutMsg());
      //emit(AuthLoginError(message: 'Something went wrong'));
      return;
    }
  }

  logout() async {
    emit(AuthLogoutLoading());
    try {
      FlutterSecureStorage storage = const FlutterSecureStorage();
      await storage.delete(key: Token.loginAccessTokenKey);
      NavigationService.navigatorKey.currentState!.pushNamedAndRemoveUntil(
        Routes.splash,
        (Route route) => false,
      );
    } catch (failure) {
      emit(AuthErrorStatusWithoutMsg());

      // emit(AuthLogoutError(message: 'Something went wrong'));
      return;
    }
  }

  getTokenAndValidate() async {
    try {
      emit(AuthTokenLoading());
      const storage = FlutterSecureStorage();
      final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(
              StringsManager.firstLaunch) ??
          true;

      if (firstLaunch) {
        storage.deleteAll();
      }

      await SharedPreferencesHelper.saveBoolToSP(
          StringsManager.firstLaunch, false);

      final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
      if (value.isEmpty) {
        emit(AuthTokenError(message: "Token not found"));
        return;
      }

      final tokenData = Token.decodeToken(value);

      if (tokenData.containsKey('exp')) {
        final exp = tokenData['exp'] ?? 0;
        final currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;

        if (currentTime < exp) {
          emit(AuthTokenSuccess());
        } else {
          emit(AuthTokenError(message: "Token expired"));
        }
      } else {
        emit(AuthTokenError(message: "Something went wrong"));
      }
    } catch (_) {
      emit(AuthErrorStatusWithoutMsg());

      // emit(AuthTokenError(message: "Something went wrong"));
    }
  }

  sendToForgetPassword({required String password}) async {
    try {
      emit(AuthForgetPassLoading());

      await AuthenticationAPI.forgetPassword(
          email: email, password: password, otpCode: otpCode);
      emit(AuthForgetPassSuccess());
    } catch (_) {
      emit(AuthErrorStatusWithoutMsg());
      // emit(AuthForgetPassError(message: 'Something went wrong'));
    }
  }
}
