import 'dart:convert';
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/menu/bloc/profile_bloc/profile_event.dart';
import 'package:syncrow_app/features/menu/bloc/profile_bloc/profile_state.dart';
import 'package:syncrow_app/features/menu/model/region_model.dart';
import 'package:syncrow_app/features/menu/model/time_zone_model.dart';
import 'package:syncrow_app/services/api/profile_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:image_picker/image_picker.dart';
import 'package:permission_handler/permission_handler.dart';

class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
  bool isSaving = false;
  bool editName = false;
  final FocusNode focusNode = FocusNode();
  File? image;
  final ImagePicker _picker = ImagePicker();
  String timeZoneSelected = '';
  String regionSelected = '';
  final TextEditingController searchController = TextEditingController();
  final TextEditingController nameController = TextEditingController(
      text: '${HomeCubit.user!.firstName} ${HomeCubit.user!.lastName}');

  List<RegionModel> allRegions = [];
  List<TimeZone> allTimeZone = [];

  ProfileBloc() : super(InitialState()) {
    on<InitialProfileEvent>(_fetchUserInfo);
    on<TimeZoneInitialEvent>(_fetchTimeZone);
    on<RegionInitialEvent>(_fetchRegion);
    on<SaveNameEvent>(saveName);
    on<SelectImageEvent>(_selectImage);
    on<ChangeNameEvent>(_changeName);
    on<SelectTimeZoneEvent>(selectTimeZone);
    on<SearchRegionEvent>(searchRegion);
    on<SearchTimeZoneEvent>(searchTimeZone);
    on<SelectRegionEvent>(selectRegion);
  }

  Future<void> saveName(SaveNameEvent event, Emitter<ProfileState> emit) async {
    if (_validateInputs()) return;
    try {
      add(const ChangeNameEvent(value: false));
      isSaving = true;
      emit(LoadingInitialState());
      final fullName = nameController.text;
      final nameParts = fullName.split(' ');
      final firstName = nameParts[0];
      final lastName = nameParts.length > 1 ? nameParts[1] : '';
      await ProfileApi.saveName(firstName: firstName, lastName: lastName);
      add(InitialProfileEvent());
      await HomeCubit.getInstance().fetchUserInfo();
      CustomSnackBar.displaySnackBar('Save Successfully');
      emit(SaveState());
    } catch (e) {
      emit(FailedState(errorMessage: e.toString()));
    } finally {
      isSaving = false;
    }
  }

  void _changeName(ChangeNameEvent event, Emitter<ProfileState> emit) {
    emit(LoadingInitialState());
    editName = event.value!;
    if (editName) {
      Future.delayed(const Duration(milliseconds: 500), () {
        focusNode.requestFocus();
      });
    } else {
      focusNode.unfocus();
    }
    emit(NameEditingState(editName: editName));
  }

  void _fetchUserInfo(
      InitialProfileEvent event, Emitter<ProfileState> emit) async {
    try {
      emit(LoadingInitialState());
      HomeCubit.user = await ProfileApi().fetchUserInfo(HomeCubit.user!.uuid);
      HomeCubit.getInstance().project = HomeCubit.user?.project;

      emit(SaveState());
    } catch (e) {
      emit(FailedState(errorMessage: e.toString()));
      return;
    }
  }

  Future _fetchTimeZone(
      TimeZoneInitialEvent event, Emitter<ProfileState> emit) async {
    emit(LoadingInitialState());
    try {
      allTimeZone = await ProfileApi.fetchTimeZone();
      emit(TimeZoneLoadedState(timezone: allTimeZone));
      return allTimeZone;
    } catch (e) {
      emit(FailedState(errorMessage: e.toString()));
      return;
    }
  }

  Future selectTimeZone(
      SelectTimeZoneEvent event, Emitter<ProfileState> emit) async {
    try {
      emit(LoadingInitialState());
      timeZoneSelected = event.val;
      await ProfileApi.saveTimeZone(regionUuid: event.val);
      CustomSnackBar.displaySnackBar('Save Successfully');
      emit(SaveState());
    } catch (e) {
      emit(FailedState(errorMessage: e.toString()));
    }
  }

  Future selectRegion(
      SelectRegionEvent event, Emitter<ProfileState> emit) async {
    try {
      emit(LoadingInitialState());
      await ProfileApi.saveRegion(regionUuid: event.val);
      CustomSnackBar.displaySnackBar('Save Successfully');
      emit(SaveState());
    } catch (e) {
      emit(FailedState(errorMessage: e.toString()));
      return;
    }
  }

  Future<void> searchRegion(
      SearchRegionEvent event, Emitter<ProfileState> emit) async {
    emit(LoadingInitialState());
    final query = event.query.toLowerCase();
    if (allRegions.isEmpty) {
      allRegions = await ProfileApi.fetchRegion();
    }
    if (query.isNotEmpty) {
      final filteredRegions = allRegions.where((region) {
        return region.name.toLowerCase().contains(query);
      }).toList();
      emit(RegionsLoadedState(regions: filteredRegions));
    } else {
      emit(RegionsLoadedState(regions: allRegions));
    }
  }

  Future<void> searchTimeZone(
      SearchTimeZoneEvent event, Emitter<ProfileState> emit) async {
    emit(LoadingInitialState());
    final query = event.query.toLowerCase();
    if (allTimeZone.isEmpty) {
      allTimeZone = await ProfileApi.fetchTimeZone();
    }
    if (query.isNotEmpty) {
      final filteredRegions = allTimeZone.where((region) {
        return region.name.toLowerCase().contains(query);
      }).toList();
      emit(TimeZoneLoadedState(timezone: filteredRegions));
    } else {
      emit(TimeZoneLoadedState(timezone: allTimeZone));
    }
  }

  void _fetchRegion(
      RegionInitialEvent event, Emitter<ProfileState> emit) async {
    try {
      emit(LoadingInitialState());
      allRegions = await ProfileApi.fetchRegion();
      emit(RegionsLoadedState(regions: allRegions));
    } catch (e) {
      emit(FailedState(errorMessage: e.toString()));
    }
  }

  Future<void> _selectImage(
      SelectImageEvent event, Emitter<ProfileState> emit) async {
    try {
      if (await _requestPermission()) {
        emit(ChangeImageState());
        final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
        if (pickedFile != null) {
          image = File(pickedFile.path);
          final bytes = image!.readAsBytesSync().lengthInBytes;
          final kb = bytes / 1024;
          final mb = kb / 1024;
          if (mb > 1) {
            image = null;
            CustomSnackBar.displaySnackBar('Image size must be 1 MB or less');
          } else {
            emit(LoadingInitialState());
            await _saveImage();
            emit(ImageSelectedState());
          }
        }
        emit(ImageSelectedState());
      } else {
        _showPermissionDeniedDialog(event.context);
      }
    } catch (_) {
      emit(const FailedState(errorMessage: 'Something went wrong'));
    }
  }

  Future<void> _saveImage() async {
    List<int> imageBytes = image!.readAsBytesSync();
    String base64Image = base64Encode(imageBytes);
    await ProfileApi.saveImage(base64Image);
  }

  void _showPermissionDeniedDialog(BuildContext context) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text('Permission Denied'),
          content: const Text(
              'Photo access is required to select an image. Please allow photo access in the app settings.'),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: const Text('Cancel'),
            ),
            TextButton(
              onPressed: () {
                openAppSettings();
              },
              child: const Text('Settings'),
            ),
          ],
        );
      },
    );
  }

  bool _validateInputs() {
    final nameError = fullNameValidator(nameController.text);
    if (nameError != null) {
      CustomSnackBar.displaySnackBar(nameError);
      return true;
    }
    return false;
  }

  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 > 2) return 'Full name can at most contain 2 parts';
    if (parts.any((part) => part.length < 2 || part.length > 30)) {
      return 'Full name parts must be between 2 and 30 characters long';
    }
    if (RegExp(r"\s{2,}").hasMatch(value)) {
      return 'Only one space is allowed between first and last names';
    }
    // Check for leading or trailing spaces
    if (value != value.trim()) {
      return 'No leading or trailing spaces allowed';
    }
    // Check if only alphabetic characters and one space are used
    if (!RegExp(r'^[A-Za-z]+(?: [A-Za-z]+)?$').hasMatch(value)) {
      return 'Only alphabetic characters and a single space are allowed';
    }
    return null;
  }

  Future<bool> _requestPermission() async {
    DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
    if (Platform.isAndroid) {
      AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
      PermissionStatus status = await Permission.photos.status;
      if (androidInfo.version.sdkInt < 33) {
        if (status.isDenied) {
          PermissionStatus status = await Permission.storage.request();
          if (status.isGranted) {
            return true;
          } else {
            return false;
          }
        }
      } else {
        if (status.isGranted) {
          return true;
        } else if (status.isDenied) {
          PermissionStatus status = await Permission.photos.request();
          if (status.isGranted) {
            return true;
          } else {
            return false;
          }
        }
      }
      return false;
    } else {
      SharedPreferences sharedPreferences =
          await SharedPreferences.getInstance();
      bool firstClick = sharedPreferences.getBool('firstPermission') ?? true;
      await sharedPreferences.setBool('firstPermission', false);
      if (firstClick == false) {
        var status = await Permission.photos.status;
        return status.isGranted;
      } else {
        return true;
      }
    }
  }
}
