import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow/core/application/di/injectable.dart';
import 'package:krow/core/data/models/event/addon_model.dart';
import 'package:krow/core/data/models/event/business_member_model.dart';
import 'package:krow/core/data/models/event/event_model.dart';
import 'package:krow/core/data/models/event/hub_model.dart';
import 'package:krow/core/data/models/event/tag_model.dart';
import 'package:krow/core/data/models/shift/business_skill_model.dart';
import 'package:krow/core/data/models/shift/department_model.dart';
import 'package:krow/core/entity/event_entity.dart';
import 'package:krow/core/entity/shift_entity.dart';
import 'package:krow/core/sevices/create_event_service/create_event_service.dart';
import 'package:krow/features/create_event/domain/create_event_repository.dart';
import 'package:krow/features/create_event/domain/input_validator.dart';
import 'package:krow/features/create_event/presentation/create_shift_details_section/bloc/create_shift_details_bloc.dart';

part 'create_event_event.dart';
part 'create_event_state.dart';

class CreateEventBloc extends Bloc<CreateEventEvent, CreateEventState> {
  CreateEventBloc() : super(CreateEventState(entity: EventEntity.empty())) {
    on<CreateEventInit>(_onInit);
    // on<CreateEventChangeContractType>(_onChangeContractType);
    on<CreateEventChangeHub>(_onChangeHub);
    // on<CreateEventChangeContractNumber>(_onChangeContractNumber);
    on<CreateEventChangePoNumber>(_onChangePoNumber);
    on<CreateEventTagSelected>(_onTagSelected);
    on<CreateEventAddShift>(_onAddShift);
    on<CreateEventRemoveShift>(_onRemoveShift);
    on<CreateEventAddInfoChange>(_onAddInfoChange);
    on<CreateEventNameChange>(_onNameChange);
    on<CreateEventToggleAddon>(_onToggleAddon);
    on<CreateEventEntityUpdatedEvent>(_onEntityUpdated);
    on<CreateEventValidateAndPreview>(_onValidateAndPreview);
    on<DeleteDraftEvent>(_onDeleteDraft);
  }

  Future<void> _onInit(
      CreateEventInit event, Emitter<CreateEventState> emit) async {
    emit(state.copyWith(inLoading: true));
    late EventEntity entity;
    bool? isEdit = event.eventModel != null;
    if (isEdit) {
      entity = EventEntity.fromEventDto(event.eventModel!);
    } else {
      entity = EventEntity.empty();
    }
    List<ShiftViewModel> shiftViewModels = [
      ...entity.shifts?.map((shiftEntity) {
            return ShiftViewModel(
              id: shiftEntity.id,
              bloc: CreateShiftDetailsBloc(expanded: !isEdit)
                ..add(CreateShiftInitializeEvent(shiftEntity)),
            );
          }).toList() ??
          [],
    ];

    emit(state.copyWith(
        recurringType: event.recurringType,
        entity: entity,
        tags: [
          //placeholder for tags - prevent UI jumping
          TagModel(id: '1', name: '                   '),
          TagModel(id: '2', name: '               '),
          TagModel(id: '3', name: '     ')
        ],
        shifts: shiftViewModels));
    List<Object> results;
    try {
      results = await Future.wait([
        getIt<CreateEventRepository>().getHubs().onError((e, s) {
          return [];
        }),
        getIt<CreateEventRepository>().getAddons().onError((e, s) => []),
        getIt<CreateEventRepository>().getTags().onError((e, s) => []),
        getIt<CreateEventRepository>().getContacts().onError((e, s) => []),
        getIt<CreateEventRepository>().getSkills().onError((e, s) => []),
      ]);
    } catch (e) {
      emit(state.copyWith(inLoading: false));
      return;
    }
    var hubs = results[0] as List<HubModel>;
    var addons = results[1] as List<AddonModel>;
    var tags = results[2] as List<TagModel>;
    var contacts = results[3] as List<BusinessMemberModel>;
    var skills = results[4] as List<BusinessSkillModel>;

    emit(state.copyWith(
        inLoading: false,
        hubs: hubs,
        tags: tags,
        addons: addons,
        contacts: contacts,
        skills: skills));
  }

  void _onChangeHub(
      CreateEventChangeHub event, Emitter<CreateEventState> emit) async {
    if (event.hub == state.entity.hub) return;
    emit(state.copyWith(
      entity: state.entity.copyWith(hub: event.hub),
    ));

    state.shifts.forEach((element) {
      element.bloc
          .add(CreateShiftAddressSelectEvent(address: event.hub.fullAddress));
    });

    var departments =
        await getIt<CreateEventRepository>().getDepartments(event.hub.id);

    emit(state.copyWith(
      departments: departments,
    ));
  }

  // void _onChangeContractType(
  //     CreateEventChangeContractType event, Emitter<CreateEventState> emit) {
  //   if (event.contractType == state.entity.contractType) return;
  //   emit(state.copyWith(
  //     entity: state.entity.copyWith(contractType: event.contractType),
  //   ));
  // }

  // void _onChangeContractNumber(
  //     CreateEventChangeContractNumber event, Emitter<CreateEventState> emit) {
  //   emit(state.copyWith(
  //     entity: state.entity.copyWith(contractNumber: event.contractNumber),
  //   ));
  // }
  //
  void _onChangePoNumber(
      CreateEventChangePoNumber event, Emitter<CreateEventState> emit) {
    emit(state.copyWith(
      entity: state.entity.copyWith(poNumber: event.poNumber),
    ));
  }

  void _onTagSelected(
      CreateEventTagSelected event, Emitter<CreateEventState> emit) {
    final tags = List<TagModel>.of(state.entity.tags ?? []);
    if (tags.any((e) => e.id == event.tag.id)) {
      tags.removeWhere((e) => e.id == event.tag.id);
    } else {
      tags.add(event.tag);
    }
    emit(state.copyWith(
      entity: state.entity.copyWith(tags: tags),
    ));
  }

  void _onAddShift(CreateEventAddShift event, Emitter<CreateEventState> emit) {
    final id = DateTime.now().millisecondsSinceEpoch.toString();
    ShiftEntity newShiftEntity = ShiftEntity.empty();

    final bloc = CreateShiftDetailsBloc(expanded: true)
      ..add(CreateShiftInitializeEvent(
        newShiftEntity,
      ));

    newShiftEntity.parentEvent = state.entity;
    state.entity.shifts?.add(newShiftEntity);

    emit(state.copyWith(
      shifts: [
        ...state.shifts,
        ShiftViewModel(id: id, bloc: bloc),
      ],
    ));
  }

  void _onRemoveShift(
      CreateEventRemoveShift event, Emitter<CreateEventState> emit) {
    emit(state.copyWith(
      entity: state.entity.copyWith(
          shifts: state.entity.shifts
              ?.where((element) => element.id != event.id)
              .toList()),
      shifts: state.shifts.where((element) => element.id != event.id).toList(),
    ));
  }

  void _onNameChange(
      CreateEventNameChange event, Emitter<CreateEventState> emit) {
    emit(state.copyWith(
      entity: state.entity.copyWith(name: event.value),
    ));
  }

  void _onAddInfoChange(
      CreateEventAddInfoChange event, Emitter<CreateEventState> emit) {
    emit(state.copyWith(
      entity: state.entity.copyWith(additionalInfo: event.value),
    ));
  }

  void _onToggleAddon(
      CreateEventToggleAddon event, Emitter<CreateEventState> emit) {
    final addons = List<AddonModel>.of(state.entity.addons ?? []);
    if (addons.any((e) => e.id == event.addon.id)) {
      addons.removeWhere((e) => e.id == event.addon.id);
    } else {
      addons.add(event.addon);
    }
    emit(state.copyWith(
      entity: state.entity.copyWith(addons: addons),
    ));
  }

  void _onEntityUpdated(
      CreateEventEntityUpdatedEvent event, Emitter<CreateEventState> emit) {
    emit(state.copyWith());
  }

  void _onValidateAndPreview(
      CreateEventValidateAndPreview event, Emitter<CreateEventState> emit) {
    var newState = CreateEventInputValidator.validateInputs(
        state.copyWith(entity: state.entity.copyWith()));
    emit(newState);
    emit(newState.copyWith(valid: false));
  }

  void _onDeleteDraft(
      DeleteDraftEvent event, Emitter<CreateEventState> emit) async {
    await getIt<CreateEventService>().deleteDraft(state.entity);
  }
}
