import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
import 'package:syncrow_web/pages/common/hour_picker_dialog.dart';
import 'package:syncrow_web/services/access_mang_api.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
import 'package:syncrow_web/utils/snack_bar.dart';

class AccessBloc extends Bloc<AccessEvent, AccessState> {
  AccessBloc() : super((AccessInitial())) {
    on<FetchTableData>(_onFetchTableData);
    on<SelectTime>(selectTime);
    on<FilterDataEvent>(_filterData);
    on<ResetSearch>(resetSearch);
    on<TabChangedEvent>(onTabChanged);
  }

  String startTime = 'Start Date';
  String endTime = 'End Date';
  int? effectiveTimeTimeStamp;
  int? expirationTimeTimeStamp;
  TextEditingController passwordName = TextEditingController();
  TextEditingController emailAuthorizer = TextEditingController();
  List<PasswordModel> filteredData = [];
  List<PasswordModel> data = [];

  Future<void> _onFetchTableData(
      FetchTableData event, Emitter<AccessState> emit) async {
    try {
      final projectUuid = await ProjectManager.getProjectUUID() ?? '';
      emit(AccessLoaded());
      data = await AccessMangApi().fetchVisitorPassword(projectUuid);
      filteredData = data;
      updateTabsCount();
      emit(TableLoaded(data));
    } catch (e) {
      emit(FailedState(e.toString()));
    }
  }

  void updateTabsCount() {
    int toBeEffectiveCount = data
        .where((item) => item.passwordStatus.value == 'To be effective')
        .length;
    int effectiveCount =
        data.where((item) => item.passwordStatus.value == 'Effective').length;
    int expiredCount =
        data.where((item) => item.passwordStatus.value == 'Expired').length;
    tabs[1] = 'To Be Effective ($toBeEffectiveCount)';
    tabs[2] = 'Effective ($effectiveCount)';
    tabs[3] = 'Expired ($expiredCount)';
  }

  int selectedIndex = 0;
  final List<String> tabs = [
    'All',
    'To Be Effective (0)',
    'Effective (0)',
    'Expired'
  ];

  Future selectFilterTap(
      TabChangedEvent event, Emitter<AccessState> emit) async {
    try {
      emit(AccessLoaded());
      selectedIndex = event.selectedIndex;
      emit(AccessInitial());
      emit(TableLoaded(data));
    } catch (e) {
      emit(FailedState(e.toString()));
      return;
    }
  }

  Future<void> selectTime(
    SelectTime event,
    Emitter<AccessState> emit,
  ) async {
    emit(AccessLoaded());
    final DateTime? picked = await showDatePicker(
      context: event.context,
      initialDate: DateTime.now(),
      firstDate: DateTime.now().add(const Duration(days: -5095)),
      lastDate: DateTime.now().add(const Duration(days: 2095)),
      builder: (BuildContext context, Widget? child) {
        return Theme(
          data: ThemeData.light().copyWith(
            colorScheme: ColorScheme.light(
              primary: ColorsManager.blackColor,
              onPrimary: Colors.white,
              onSurface: ColorsManager.grayColor,
            ),
            textButtonTheme: TextButtonThemeData(
              style: TextButton.styleFrom(
                foregroundColor: Colors.blue,
              ),
            ),
          ),
          child: child!,
        );
      },
    );
    if (picked != null) {
      final TimeOfDay? timePicked = await showHourPicker(
        context: event.context,
        initialTime: TimeOfDay.now(),
      );

      if (timePicked != null) {
        final DateTime selectedDateTime = DateTime(
          picked.year,
          picked.month,
          picked.day,
          timePicked.hour,
          timePicked.minute,
        );
        final int selectedTimestamp =
            selectedDateTime.millisecondsSinceEpoch ~/ 1000;
        if (event.isStart) {
          if (expirationTimeTimeStamp != null &&
              selectedTimestamp > expirationTimeTimeStamp!) {
            CustomSnackBar.displaySnackBar(
                'Effective Time cannot be later than Expiration Time.');
          } else {
            startTime = selectedDateTime.toString().split('.').first;
            effectiveTimeTimeStamp = selectedTimestamp;
          }
        } else {
          if (effectiveTimeTimeStamp != null &&
              selectedTimestamp < effectiveTimeTimeStamp!) {
            CustomSnackBar.displaySnackBar(
                'Expiration Time cannot be earlier than Effective Time.');
          } else {
            endTime = selectedDateTime.toString().split('.').first;
            expirationTimeTimeStamp = selectedTimestamp;
          }
        }
      }
    }
    emit(ChangeTimeState());
  }

  Future<void> _filterData(
      FilterDataEvent event, Emitter<AccessState> emit) async {
    emit(AccessLoaded());
    try {
      // Convert search text to lower case for case-insensitive search
      final searchText = event.passwordName?.toLowerCase() ?? '';
      final searchEmailText = event.emailAuthorizer?.toLowerCase() ?? '';
      filteredData = data.where((item) {
        bool matchesCriteria = true;
        // Convert timestamp to DateTime and extract date component
        DateTime effectiveDate = DateTime.fromMillisecondsSinceEpoch(
                int.parse(item.effectiveTime.toString()) * 1000)
            .toUtc()
            .toLocal();
        DateTime invalidDate = DateTime.fromMillisecondsSinceEpoch(
                int.parse(item.invalidTime.toString()) * 1000)
            .toUtc()
            .toLocal();
        DateTime effectiveDateAndTime = DateTime(
            effectiveDate.year,
            effectiveDate.month,
            effectiveDate.day,
            effectiveDate.hour,
            effectiveDate.minute);
        DateTime invalidDateAndTime = DateTime(
            invalidDate.year,
            invalidDate.month,
            invalidDate.day,
            invalidDate.hour,
            invalidDate.minute);

        // Filter by password name, making the search case-insensitive
        if (searchText.isNotEmpty) {
          final bool matchesName =
              item.passwordName.toString().toLowerCase().contains(searchText);
          if (!matchesName) {
            matchesCriteria = false;
          }
        }
        if (searchEmailText.isNotEmpty) {
          final bool matchesName = item.authorizerEmail
              .toString()
              .toLowerCase()
              .contains(searchEmailText);
          if (!matchesName) {
            matchesCriteria = false;
          }
        }
        // Filter by start date only
        if (event.startTime != null && event.endTime == null) {
          DateTime startDateTime =
              DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000)
                  .toUtc()
                  .toLocal();
          startDateTime = DateTime(startDateTime.year, startDateTime.month,
              startDateTime.day, startDateTime.hour, startDateTime.minute);
          if (effectiveDateAndTime.isBefore(startDateTime)) {
            matchesCriteria = false;
          }
        }
        // Filter by end date only
        if (event.endTime != null && event.startTime == null) {
          DateTime startDateTime =
              DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000)
                  .toUtc()
                  .toLocal();
          startDateTime = DateTime(startDateTime.year, startDateTime.month,
              startDateTime.day, startDateTime.hour, startDateTime.minute);
          if (invalidDateAndTime.isAfter(startDateTime)) {
            matchesCriteria = false;
          }
        }

        // Filter by both start date and end date
        if (event.startTime != null && event.endTime != null) {
          DateTime startDateTime =
              DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000)
                  .toUtc()
                  .toLocal();
          DateTime endDateTime =
              DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000)
                  .toUtc()
                  .toLocal();
          startDateTime = DateTime(startDateTime.year, startDateTime.month,
              startDateTime.day, startDateTime.hour, startDateTime.minute);
          endDateTime = DateTime(endDateTime.year, endDateTime.month,
              endDateTime.day, endDateTime.hour, endDateTime.minute);
          if (effectiveDateAndTime.isBefore(startDateTime) ||
              invalidDateAndTime.isAfter(endDateTime)) {
            matchesCriteria = false;
          }
        }

        // Filter by selected tab index
        if (event.selectedTabIndex == 1 &&
            item.passwordStatus.value != 'To be effective') {
          matchesCriteria = false;
        } else if (event.selectedTabIndex == 2 &&
            item.passwordStatus.value != 'Effective') {
          matchesCriteria = false;
        } else if (event.selectedTabIndex == 3 &&
            item.passwordStatus.value != 'Expired') {
          matchesCriteria = false;
        }

        return matchesCriteria;
      }).toList();

      emit(TableLoaded(filteredData));
    } catch (e) {
      emit(FailedState(e.toString()));
    }
  }

  resetSearch(ResetSearch event, Emitter<AccessState> emit) async {
    emit(AccessLoaded());
    startTime = 'Start Time';
    endTime = 'End Time';
    passwordName.clear();
    emailAuthorizer.clear();
    selectedIndex = 0;
    effectiveTimeTimeStamp = null;
    expirationTimeTimeStamp = null;
    filteredData = List.from(data);
    emit(TableLoaded(filteredData));
  }

  String timestampToDate(dynamic timestamp) {
    DateTime dateTime =
        DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
    return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')} "
        " ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}";
  }

  Future<void> onTabChanged(
      TabChangedEvent event, Emitter<AccessState> emit) async {
    try {
      emit(AccessLoaded());
      selectedIndex = event.selectedIndex;
      switch (selectedIndex) {
        case 0: // All
          filteredData = data;
          break;
        case 1: // To Be Effective
          filteredData = data
              .where((item) => item.passwordStatus.value == "To Be Effective")
              .toList();
          break;
        case 2: // Effective
          filteredData = data
              .where((item) => item.passwordStatus.value == "Effective")
              .toList();
          break;
        case 3: // Expired
          filteredData = data
              .where((item) => item.passwordStatus.value == "Expired")
              .toList();
          break;
        default:
          filteredData = data;
      }
      add(FilterDataEvent(
          selectedTabIndex: selectedIndex,
          passwordName: passwordName.text.toLowerCase(),
          emailAuthorizer: emailAuthorizer.text.toLowerCase(),
          startTime: effectiveTimeTimeStamp,
          endTime: expirationTimeTimeStamp));
      emit(TableLoaded(filteredData));
    } catch (e) {
      emit(FailedState(e.toString()));
    }
  }
}
