import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../domain/arguments/save_experience_arguments.dart';
import '../../domain/usecases/get_staff_industries_usecase.dart';
import '../../domain/usecases/get_staff_skills_usecase.dart';
import '../../domain/usecases/save_experience_usecase.dart';

// Events
abstract class ExperienceEvent extends Equatable {
  const ExperienceEvent();

  @override
  List<Object?> get props => [];
}

class ExperienceLoaded extends ExperienceEvent {}

class ExperienceIndustryToggled extends ExperienceEvent {
  final Industry industry;
  const ExperienceIndustryToggled(this.industry);

  @override
  List<Object?> get props => [industry];
}

class ExperienceSkillToggled extends ExperienceEvent {
  final String skill;
  const ExperienceSkillToggled(this.skill);

  @override
  List<Object?> get props => [skill];
}

class ExperienceCustomSkillAdded extends ExperienceEvent {
  final String skill;
  const ExperienceCustomSkillAdded(this.skill);

  @override
  List<Object?> get props => [skill];
}

class ExperienceSubmitted extends ExperienceEvent {}

// State
enum ExperienceStatus { initial, loading, success, failure }

class ExperienceState extends Equatable {
  final ExperienceStatus status;
  final List<Industry> selectedIndustries;
  final List<String> selectedSkills;
  final List<Industry> availableIndustries;
  final List<ExperienceSkill> availableSkills;
  final String? errorMessage;

  const ExperienceState({
    this.status = ExperienceStatus.initial,
    this.selectedIndustries = const [],
    this.selectedSkills = const [],
    this.availableIndustries = const [],
    this.availableSkills = const [],
    this.errorMessage,
  });

  ExperienceState copyWith({
    ExperienceStatus? status,
    List<Industry>? selectedIndustries,
    List<String>? selectedSkills,
    List<Industry>? availableIndustries,
    List<ExperienceSkill>? availableSkills,
    String? errorMessage,
  }) {
    return ExperienceState(
      status: status ?? this.status,
      selectedIndustries: selectedIndustries ?? this.selectedIndustries,
      selectedSkills: selectedSkills ?? this.selectedSkills,
      availableIndustries: availableIndustries ?? this.availableIndustries,
      availableSkills: availableSkills ?? this.availableSkills,
      errorMessage: errorMessage ?? this.errorMessage,
    );
  }

  @override
  List<Object?> get props => [
    status,
    selectedIndustries,
    selectedSkills,
    availableIndustries,
    availableSkills,
    errorMessage,
  ];
}

// BLoC
class ExperienceBloc extends Bloc<ExperienceEvent, ExperienceState> {

  final GetStaffIndustriesUseCase getIndustries;
  final GetStaffSkillsUseCase getSkills;
  final SaveExperienceUseCase saveExperience;

  ExperienceBloc({
    required this.getIndustries,
    required this.getSkills,
    required this.saveExperience,
  }) : super(const ExperienceState(
          availableIndustries: Industry.values,
          availableSkills: ExperienceSkill.values,
        )) {
    on<ExperienceLoaded>(_onLoaded);
    on<ExperienceIndustryToggled>(_onIndustryToggled);
    on<ExperienceSkillToggled>(_onSkillToggled);
    on<ExperienceCustomSkillAdded>(_onCustomSkillAdded);
    on<ExperienceSubmitted>(_onSubmitted);

    add(ExperienceLoaded());
  }

  Future<void> _onLoaded(
    ExperienceLoaded event,
    Emitter<ExperienceState> emit,
  ) async {
    emit(state.copyWith(status: ExperienceStatus.loading));
    try {
      final results = await Future.wait([
        getIndustries(),
        getSkills(),
      ]);

      emit(state.copyWith(
        status: ExperienceStatus.initial,
        selectedIndustries: results[0]
            .map((e) => Industry.fromString(e))
            .whereType<Industry>()
            .toList(),
        selectedSkills: results[1],
      ));
    } catch (e) {
      emit(state.copyWith(
        status: ExperienceStatus.failure,
        errorMessage: e.toString(),
      ));
    }
  }

  void _onIndustryToggled(
    ExperienceIndustryToggled event,
    Emitter<ExperienceState> emit,
  ) {
    final industries = List<Industry>.from(state.selectedIndustries);
    if (industries.contains(event.industry)) {
      industries.remove(event.industry);
    } else {
      industries.add(event.industry);
    }
    emit(state.copyWith(selectedIndustries: industries));
  }

  void _onSkillToggled(
    ExperienceSkillToggled event,
    Emitter<ExperienceState> emit,
  ) {
    final skills = List<String>.from(state.selectedSkills);
    if (skills.contains(event.skill)) {
      skills.remove(event.skill);
    } else {
      skills.add(event.skill);
    }
    emit(state.copyWith(selectedSkills: skills));
  }

  void _onCustomSkillAdded(
    ExperienceCustomSkillAdded event,
    Emitter<ExperienceState> emit,
  ) {
    if (!state.selectedSkills.contains(event.skill)) {
      final skills = List<String>.from(state.selectedSkills)..add(event.skill);
      emit(state.copyWith(selectedSkills: skills));
    }
  }

  Future<void> _onSubmitted(
    ExperienceSubmitted event,
    Emitter<ExperienceState> emit,
  ) async {
    emit(state.copyWith(status: ExperienceStatus.loading));
    try {
      await saveExperience(
        SaveExperienceArguments(
          industries: state.selectedIndustries.map((e) => e.value).toList(),
          skills: state.selectedSkills,
        ),
      );
      emit(state.copyWith(status: ExperienceStatus.success));
    } catch (e) {
      emit(state.copyWith(
        status: ExperienceStatus.failure,
        errorMessage: e.toString(),
      ));
    }
  }
}
