package com.airlock.iam.admin.infrastructure.event;

import com.airlock.iam.admin.api.domain.model.administrator.AdminEventSource;
import com.airlock.iam.admin.api.domain.service.user.ManagedUserRepository;
import com.airlock.iam.airlock2fa.api.domain.model.Airlock2FADeviceDeleted;
import com.airlock.iam.base.api.domain.model.event.DomainEvent;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.base.infrastructure.event.DomainEventValuesProvider;
import com.airlock.iam.common.api.domain.model.event.AuthenticationMethodChanged;
import com.airlock.iam.common.api.domain.model.event.ContextDataChanged;
import com.airlock.iam.common.api.domain.model.event.CrontoDeviceDeleted;
import com.airlock.iam.common.api.domain.model.event.DeviceTokenDeleted;
import com.airlock.iam.common.api.domain.model.event.EmailAddressAdded;
import com.airlock.iam.common.api.domain.model.event.EmailAddressChanged;
import com.airlock.iam.common.api.domain.model.event.EmailAddressDeleted;
import com.airlock.iam.common.api.domain.model.event.MtanTokenDeleted;
import com.airlock.iam.common.api.domain.model.event.MtanTokenPhoneNumberChanged;
import com.airlock.iam.common.api.domain.model.event.MtanTokenRegistered;
import com.airlock.iam.common.api.domain.model.event.UserCreated;
import com.airlock.iam.common.api.domain.model.event.UserDeleted;
import com.airlock.iam.common.api.domain.model.event.UserEvent;
import com.airlock.iam.common.api.domain.model.event.UserLocked;
import com.airlock.iam.common.api.domain.model.event.UserRolesChanged;
import com.airlock.iam.common.api.domain.model.event.UserUnlocked;
import com.airlock.iam.common.infrastructure.event.CommonEventValues;
import com.airlock.iam.common.infrastructure.event.CommonUserEventValuesProvider;
import com.airlock.iam.common.infrastructure.event.CommonUserEventValuesProvider.EventValuesProvider;
import com.airlock.iam.fido.api.domain.model.event.FidoCredentialDeleted;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class AdminappEventValuesProvider implements DomainEventValuesProvider {
   private static final List<EventValuesProvider<?>> EVENT_SPECIFIC_PROVIDERS = List.of(
      CommonUserEventValuesProvider.provider(Airlock2FADeviceDeleted.class, AdminappEventValues.AIRLOCK_2FA_DEVICE_DELETED_VALUES),
      CommonUserEventValuesProvider.provider(AuthenticationMethodChanged.class, CommonEventValues.AUTHENTICATION_METHOD_CHANGED_VALUES),
      CommonUserEventValuesProvider.provider(CrontoDeviceDeleted.class, CommonEventValues.CRONTO_DEVICE_DELETED_VALUES),
      CommonUserEventValuesProvider.provider(DeviceTokenDeleted.class, CommonEventValues.DEVICE_TOKEN_DELETED_VALUES),
      CommonUserEventValuesProvider.provider(EmailAddressAdded.class, CommonEventValues.EMAIL_ADDRESS_ADDED_VALUES),
      CommonUserEventValuesProvider.provider(EmailAddressChanged.class, CommonEventValues.EMAIL_ADDRESS_CHANGED_VALUES),
      CommonUserEventValuesProvider.provider(EmailAddressDeleted.class, CommonEventValues.EMAIL_ADDRESS_DELETED_VALUES),
      CommonUserEventValuesProvider.provider(UserRolesChanged.class, CommonEventValues.USER_ROLES_CHANGED_VALUES),
      CommonUserEventValuesProvider.provider(FidoCredentialDeleted.class, AdminappEventValues.FIDO_CREDENTIAL_DELETED_VALUES),
      CommonUserEventValuesProvider.provider(MtanTokenDeleted.class, CommonEventValues.MTAN_TOKEN_DELETED_VALUES),
      CommonUserEventValuesProvider.provider(MtanTokenPhoneNumberChanged.class, CommonEventValues.MTAN_NUMBER_CHANGED_VALUES),
      CommonUserEventValuesProvider.provider(MtanTokenRegistered.class, CommonEventValues.MTAN_TOKEN_REGISTERED_VALUES),
      CommonUserEventValuesProvider.provider(ContextDataChanged.class, CommonEventValues.CONTEXT_DATA_CHANGED_VALUES),
      CommonUserEventValuesProvider.provider(UserLocked.class, CommonEventValues.USER_LOCKED_VALUES),
      CommonUserEventValuesProvider.provider(UserUnlocked.class, CommonEventValues.USER_UNLOCKED_VALUES),
      CommonUserEventValuesProvider.provider(UserCreated.class, CommonEventValues.USER_CREATED_VALUES),
      CommonUserEventValuesProvider.provider(UserDeleted.class, CommonEventValues.USER_DELETED_VALUES)
   );
   private final Provider<ManagedUserRepository> repository;

   @Inject
   public AdminappEventValuesProvider(Provider<ManagedUserRepository> repository) {
      this.repository = repository;
   }

   public Map<String, Object> provideValueMapForEvent(DomainEvent event) {
      Map<String, Object> values = new HashMap<>(CommonUserEventValuesProvider.provideGenericEventValues(event));
      values.putAll(this.provideApplicationSpecificEventValues(event));
      values.putAll(CommonUserEventValuesProvider.provideEventSpecificValues(event, EVENT_SPECIFIC_PROVIDERS));
      return Collections.unmodifiableMap(values);
   }

   private Map<String, Object> provideApplicationSpecificEventValues(DomainEvent event) {
      Map<String, Object> values = new HashMap<>();
      if (event instanceof UserEvent userEvent) {
         values.putAll(this.userContextData(userEvent.userId()));
      }

      if (event.source() instanceof AdminEventSource adminSource) {
         values.put("event.source.adminId", adminSource.adminId().getValue());
      }

      return values;
   }

   private Map<String, Object> userContextData(UserId userId) {
      return ((ManagedUserRepository)this.repository.get()).findById(userId).map(user -> user.getContextData().asKeyValueMap()).orElse(Collections.emptyMap());
   }
}
