import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:syncrow_web/pages/auth/bloc/auth_event.dart';
import 'package:syncrow_web/pages/auth/bloc/auth_state.dart';
import 'package:syncrow_web/pages/auth/model/login_with_email_model.dart';
import 'package:syncrow_web/pages/auth/model/region_model.dart';
import 'package:syncrow_web/pages/auth/model/token.dart';
import 'package:syncrow_web/pages/auth/model/user_model.dart';
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
import 'package:syncrow_web/services/api/api_exception.dart';
import 'package:syncrow_web/services/auth_api.dart';
import 'package:syncrow_web/utils/constants/strings_manager.dart';
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
import 'package:syncrow_web/utils/snack_bar.dart';

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  AuthBloc() : super(LoginInitial()) {
    on<LoginButtonPressed>(_login);
    on<CheckBoxEvent>(checkBoxToggle);
    on<ChangePasswordEvent>(changePassword);
    on<StartTimerEvent>(_onStartTimer);
    on<StopTimerEvent>(_onStopTimer);
    on<UpdateTimerEvent>(_onUpdateTimer);
    on<PasswordVisibleEvent>(_passwordVisible);
    on<RegionInitialEvent>(_fetchRegion);
    on<SelectRegionEvent>(selectRegion);
    on<CheckEnableEvent>(checkEnable);
    on<ChangeValidateEvent>(changeValidate);
  }

  ////////////////////////////// forget password //////////////////////////////////
  final TextEditingController forgetEmailController = TextEditingController();
  final TextEditingController forgetPasswordController =
      TextEditingController();
  final TextEditingController forgetOtp = TextEditingController();
  final forgetFormKey = GlobalKey<FormState>();
  final forgetEmailKey = GlobalKey<FormState>();
  final forgetRegionKey = GlobalKey<FormState>();
  late bool checkValidate = false;

  Timer? _timer;
  int _remainingTime = 0;
  List<RegionModel>? regionList = [RegionModel(name: 'name', id: 'id')];

  Future _onStartTimer(StartTimerEvent event, Emitter<AuthState> emit) async {
    if (_validateInputs(emit)) return;
    if (_timer != null && _timer!.isActive) {
      return;
    }
    _remainingTime = 1;
    add(UpdateTimerEvent(
        remainingTime: _remainingTime, isButtonEnabled: false));
    try {
      forgetEmailValidate = '';
      _remainingTime = (await AuthenticationAPI.sendOtp(
        email: forgetEmailController.text,
      ))!;
    } on DioException catch (e) {
      if (e.response!.statusCode == 400) {
        final errorData = e.response!.data;
        String errorMessage = errorData['message'];
        if (errorMessage == 'User not found') {
          validate = 'Invalid Credential';
          emit(AuthInitialState());
          return 1;
        } else {
          validate = '';
          _remainingTime = errorData['data']['cooldown'] ?? 1;
          emit(AuthInitialState());
        }
      } else {
        emit(AuthInitialState());

        return 1;
      }
      emit(AuthInitialState());
    } catch (e) {
      emit(AuthInitialState());

      return 1;
    }

    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      _remainingTime--;
      if (_remainingTime <= 0) {
        _timer?.cancel();
        add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
      } else {
        add(UpdateTimerEvent(
            remainingTime: _remainingTime, isButtonEnabled: false));
      }
    });
  }

  void _onStopTimer(StopTimerEvent event, Emitter<AuthState> emit) {
    _timer?.cancel();
    emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
  }

  Future<void> changePassword(
      ChangePasswordEvent event, Emitter<AuthState> emit) async {
    emit(LoadingForgetState());
    try {
      var response = await AuthenticationAPI.verifyOtp(
          email: forgetEmailController.text, otpCode: forgetOtp.text);
      if (response == true) {
        await AuthenticationAPI.forgetPassword(
            otpCode: forgetOtp.text,
            password: forgetPasswordController.text,
            email: forgetEmailController.text);
        _timer?.cancel();
        emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
        emit(SuccessForgetState());
      }
    } on APIException catch (e) {
      final errorMessage = e.message;
      validate = errorMessage;
      emit(AuthInitialState());
    }
  }

  String? validateCode(String? value) {
    if (value == null || value.isEmpty) {
      return 'Code is required';
    }
    return null;
  }

  void _onUpdateTimer(UpdateTimerEvent event, Emitter<AuthState> emit) {
    emit(TimerState(
        isButtonEnabled: event.isButtonEnabled,
        remainingTime: event.remainingTime));
  }

  /////////////////////////////////////  login  /////////////////////////////////////
  final TextEditingController loginEmailController = TextEditingController();
  final TextEditingController loginPasswordController = TextEditingController();
  final loginFormKey = GlobalKey<FormState>();
  bool isChecked = true;
  bool obscureText = true;
  String newPassword = '';
  String maskedEmail = '';
  String otpCode = '';
  String validate = '';
  String forgetValidate = '';
  String forgetEmailValidate = '';
  // String regionUuid = '';
  static Token token = Token.emptyConstructor();
  static UserModel? user;
  bool showValidationMessage = false;

  void _login(LoginButtonPressed event, Emitter<AuthState> emit) async {
    emit(AuthLoading());
    if (isChecked) {
      try {
        if (event.username.isEmpty || event.password.isEmpty) {
          CustomSnackBar.displaySnackBar('Please enter your credentials');
          emit(const LoginFailure(error: 'Something went wrong'));
          return;
        }

        token = await AuthenticationAPI.loginWithEmail(
          model: LoginWithEmailModel(
            email: event.username.toLowerCase(),
            password: event.password,
          ),
        );
      } on APIException catch (e) {
        validate = e.message;
        emit(LoginFailure(error: validate));
        return;
      } catch (e) {
        validate = 'Something went wrong';
        emit(LoginFailure(error: validate));
        return;
      }

      if (token.accessTokenIsNotEmpty) {
        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);
        loginEmailController.clear();
        loginPasswordController.clear();
        emit(LoginSuccess());
      } else {
        emit(const LoginFailure(error: 'Something went wrong'));
      }
    } else {
      emit(const LoginFailure(error: 'Accept terms and condition'));
    }
  }

  checkBoxToggle(
    CheckBoxEvent event,
    Emitter<AuthState> emit,
  ) {
    emit(AuthLoading());
    isChecked = event.newValue!;
    add(CheckEnableEvent());
    emit(LoginInitial());
  }

  // checkOtpCode(
  //   ChangePasswordEvent event,
  //   Emitter<AuthState> emit,
  // ) async {
  //   emit(LoadingForgetState());
  //   await AuthenticationAPI.verifyOtp(
  //       email: forgetEmailController.text, otpCode: forgetOtp.text);
  //   emit(SuccessForgetState());
  // }

  void _passwordVisible(PasswordVisibleEvent event, Emitter<AuthState> emit) {
    emit(AuthLoading());
    obscureText = !event.newValue!;
    emit(PasswordVisibleState());
  }

  void launchURL(String url) {}

  /////////////////////////////////////VALIDATORS/////////////////////////////////////
  String? validatePassword(String? value) {
    if (value == null || value.isEmpty) {
      return '';
    }
    return null;
  }

  String? validateEmail(String? value) {
    if (value == null || value.isEmpty) {
      return 'Email is required';
    } else if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value)) {
      return 'Enter a valid email address';
    }
    // else if (regionUuid == '') {
    //   return 'Please select your region';
    // }
    validate = '';
    return null;
  }

  String? loginValidateEmail(String? value) {
    if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value!)) {
      return '';
    }
    return null;
  }

  bool _validateInputs(Emitter<AuthState> emit) {
    emit(LoadingForgetState());
    final nameError = validateEmail(forgetEmailController.text);
    if (nameError != null) {
      forgetEmailValidate = nameError;
      emit(AuthInitialState());
      // emit(FailureForgetState(error: nameError));
      return true;
    }
    return false;
  }

  String? validateRegion(String? value) {
    if (value == null || value.isEmpty) {
      return 'Please select a region';
    }
    return null;
  }

  String? passwordValidator(String? value) {
    if (value == null || value.isEmpty) {
      return 'Please enter your password';
    }
    List<String> validationErrors = [];

    if (!RegExp(r'^(?=.*[a-z])').hasMatch(value)) {
      validationErrors.add(' - one lowercase letter');
    }
    if (!RegExp(r'^(?=.*[A-Z])').hasMatch(value)) {
      validationErrors.add(' - one uppercase letter');
    }
    if (!RegExp(r'^(?=.*\d)').hasMatch(value)) {
      validationErrors.add(' - one number');
    }
    if (!RegExp(r'^(?=.*[@$!%*?&])').hasMatch(value)) {
      validationErrors.add(' - one special character');
    }
    if (value.length < 8) {
      validationErrors.add(' - minimum 8 characters');
    }

    if (validationErrors.isNotEmpty) {
      return 'Password must contain at least:\n${validationErrors.join('\n')}';
    }

    return null;
  }

  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';
    }
    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 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';
  }

  static Future<String> getTokenAndValidate() async {
    try {
      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) {
        return 'Token not found';
      }
      final tokenData = Token.decodeToken(value);
      if (tokenData.containsKey('exp')) {
        final exp = tokenData['exp'] ?? 0;
        final currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;
        if (currentTime < exp) {
          return 'Success';
        } else {
          return 'expired';
        }
      } else {
        return 'Something went wrong';
      }
    } catch (_) {
      return 'Something went wrong';
    }
  }

  void _fetchRegion(RegionInitialEvent event, Emitter<AuthState> emit) async {
    try {
      emit(AuthLoading());
      regionList = await AuthenticationAPI.fetchRegion();
      emit(AuthInitialState());
    } catch (e) {
      emit(LoginFailure(error: e.toString()));
    }
  }

  Future selectRegion(SelectRegionEvent event, Emitter<AuthState> emit) async {
    try {
      emit(AuthLoading());
      // regionUuid = event.val;
      add(CheckEnableEvent());
      emit(AuthInitialState());
    } catch (e) {
      emit(FailureForgetState(error: e.toString()));
      return;
    }
  }

  String formattedTime(int time) {
    final int days = (time / 86400).floor(); // 86400 seconds in a day
    final int hours = ((time % 86400) / 3600).floor();
    final int minutes = (((time % 86400) % 3600) / 60).floor();
    final int seconds = (((time % 86400) % 3600) % 60).floor();

    final String formattedTime = [
      if (days > 0) '${days}d', // Append 'd' for days
      if (days > 0 || hours > 0)
        hours
            .toString()
            .padLeft(2, '0'), // Show hours if there are days or hours
      minutes.toString().padLeft(2, '0'),
      seconds.toString().padLeft(2, '0'),
    ].join(':');

    return formattedTime;
  }

  bool checkEnable(
    CheckEnableEvent event,
    Emitter<AuthState> emit,
  ) {
    emit(AuthLoading());
    checkValidate = isChecked == true &&
        loginPasswordController.text.isNotEmpty &&
        loginEmailController.text.isNotEmpty;
    emit(LoginInitial());
    return checkValidate;
  }

  changeValidate(
    ChangeValidateEvent event,
    Emitter<AuthState> emit,
  ) {
    emit(AuthLoading());
    validate = '';
    emit(LoginInitial());
  }

  changeForgetValidate(
    ChangeValidateEvent event,
    Emitter<AuthState> emit,
  ) {
    emit(AuthLoading());
    forgetValidate = '';
    emit(LoginInitial());
  }

  static Future<void> logout(BuildContext context) async {
    const storage = FlutterSecureStorage();
    context.read<SpaceTreeBloc>().add(ClearAllData());
    user = null;
    context.read<HomeBloc>().user = null;
    await Future.wait<void>([
      ProjectManager.clearProjectUUID(),
      storage.deleteAll(),
    ]);
  }
}
