import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/features/master_data/staff/data/staff_repository.dart';
import 'package:flux/features/master_data/staff/models/staff_member_model.dart';
import 'package:flux/features/master_data/store/models/store_model.dart';
import 'package:get_it/get_it.dart';

part 'staff_state.dart';

class StaffCubit extends Cubit<StaffState> {
  final StaffRepository _repository = GetIt.I.get<StaffRepository>();
  final SessionCubit _sessionCubit = GetIt.I<SessionCubit>();

  StaffCubit() : super(const StaffState()) {
    init();
  }

  Future<void> init() async {
    emit(state.copyWith(status: StaffStatus.loading, error: null));
    try {
      final allStaff = await _repository.getStaffMembers(
        _sessionCubit.state.company!.id!,
      );

      emit(state.copyWith(status: StaffStatus.success, allStaff: allStaff));
    } catch (e) {
      emit(state.copyWith(status: StaffStatus.error, error: e.toString()));
    }
  }

  // Carica tutto lo staff della compagnia
  Future<void> loadAllStaff() async {
    emit(state.copyWith(status: StaffStatus.loading, error: null));
    try {
      final staff = await _repository.getStaffMembers(
        _sessionCubit.state.company!.id!,
      );
      final Map<String, List<StoreModel>> storesByStaff = {};
      for (StaffMemberModel member in staff) {
        storesByStaff[member.id!] = await loadStoresByStaff(member.id!);
      }
      emit(
        state.copyWith(
          status: StaffStatus.success,
          allStaff: staff,
          storesByStaff: storesByStaff,
        ),
      );
    } catch (e) {
      emit(state.copyWith(status: StaffStatus.error, error: e.toString()));
    }
  }

  Future<List<StoreModel>> loadStoresByStaff(String staffId) async {
    try {
      emit(state.copyWith(error: null));
      return await _repository.getStaffMemberStore(staffId);
    } catch (e) {
      emit(state.copyWith(error: e.toString()));
      return [];
    }
  }

  // Carica lo staff di uno specifico negozio e aggiorna la mappa
  Future<void> loadStaffForStore(String storeId) async {
    emit(state.copyWith(error: null));
    try {
      final staffInStore = await _repository.getStaffMembersInStore(storeId);
      final newMap = Map<String, List<StaffMemberModel>>.from(
        state.staffByStore,
      );
      newMap[storeId] = staffInStore;
      emit(state.copyWith(staffByStore: newMap, storeStaff: staffInStore));
    } catch (e) {
      emit(state.copyWith(status: StaffStatus.error, error: e.toString()));
    }
  }

  // Salva o aggiorna un membro
  Future<void> saveStaffMember(StaffMemberModel member) async {
    emit(state.copyWith(status: StaffStatus.loading, error: null));
    try {
      await _repository.saveStaffMember(member);
      await loadAllStaff(); // Ricarichiamo la lista aggiornata
    } catch (e) {
      emit(state.copyWith(status: StaffStatus.error, error: e.toString()));
    }
  }

  Future<void> inviteStaffMember({
    required StaffMemberModel member,
    required List<String> selectedStoreIds,
  }) async {
    emit(state.copyWith(status: StaffStatus.loading, error: null));

    try {
      // 1. Invitiamo il membro e ci facciamo dare l'ID
      final newStaffId = await _repository.inviteStaffMember(member);

      // 2. Assegniamo i negozi uno ad uno (usando il metodo che avevi già nel repo!)
      if (selectedStoreIds.isNotEmpty) {
        final List<Future> assignTasks = [];
        for (var storeId in selectedStoreIds) {
          assignTasks.add(_repository.assignStaffToStore(newStaffId, storeId));
        }
        await Future.wait(assignTasks); // In parallelo per la massima velocità
      }

      // 3. Ricarichiamo la lista globale così la UI si aggiorna
      await loadAllStaff();
      // (Nota: se hai un loadStaffForStore o loadAllStaff, chiamalo qui per rinfrescare lo stato)

      emit(state.copyWith(status: StaffStatus.success));
    } catch (e) {
      emit(state.copyWith(status: StaffStatus.error, error: e.toString()));
    }
  }

  Future<void> resetPassword(String email) async {
    try {
      await _repository.resetPassword(email);
      emit(state.copyWith(status: StaffStatus.emailSent, error: null));
    } catch (e) {
      emit(state.copyWith(status: StaffStatus.error, error: e.toString()));
    }
  }

  // Associa un dipendente a un negozio
  Future<void> assignMemberToStore(String staffId, String storeId) async {
    try {
      await _repository.assignStaffToStore(staffId, storeId);
      final stuffStores = await loadStoresByStaff(staffId);
      final Map<String, List<StoreModel>> storesByStaff = Map.from(
        state.storesByStaff,
      );
      storesByStaff[staffId] = stuffStores;
      emit(state.copyWith(storesByStaff: storesByStaff, error: null));
    } catch (e) {
      emit(
        state.copyWith(
          status: StaffStatus.error,
          error: "Errore nell'assegnazione: $e",
        ),
      );
    }
  }

  // Rimuove un dipendente da un negozio
  Future<void> removeMemberFromStore(String staffId, String storeId) async {
    try {
      await _repository.removeStaffFromStore(staffId, storeId);
      final stuffStores = await loadStoresByStaff(staffId);
      final Map<String, List<StoreModel>> storesByStaff = Map.from(
        state.storesByStaff,
      );
      storesByStaff[staffId] = stuffStores;
      emit(state.copyWith(storesByStaff: storesByStaff, error: null));
    } catch (e) {
      emit(
        state.copyWith(
          status: StaffStatus.error,
          error: "Errore nella rimozione: $e",
        ),
      );
    }
  }

  Future<void> saveStaffWithStores({
    required StaffMemberModel member,
    required List<String> selectedStoreIds,
  }) async {
    emit(state.copyWith(status: StaffStatus.loading, error: null));
    try {
      // 1. Salva o aggiorna l'anagrafica (ci serve l'ID)
      // Se è un nuovo membro, Supabase ci restituirà l'ID generato
      final savedMember = await _repository.saveStaffMember(member);
      final String staffId = savedMember.id!;

      // 2. Sincronizzazione Negozi
      // Per semplicità e pulizia, rimuoviamo le vecchie assegnazioni e inseriamo le nuove
      // (Oppure facciamo un confronto tra liste, ma il reset & rewrite è più sicuro qui)
      await _repository.clearStoreAssignments(staffId);

      if (selectedStoreIds.isNotEmpty) {
        await Future.wait(
          selectedStoreIds.map(
            (storeId) => _repository.assignStaffToStore(staffId, storeId),
          ),
        );
      }

      // 3. Rinfresca i dati
      await loadAllStaff();

      emit(state.copyWith(status: StaffStatus.success));
    } catch (e) {
      emit(state.copyWith(status: StaffStatus.error, error: e.toString()));
    }
  }
}
