package com.airlock.iam.login.app.infrastructure.event;

import com.airlock.iam.airlock2fa.api.domain.model.Airlock2FADeviceActivated;
import com.airlock.iam.airlock2fa.api.domain.model.Airlock2FADeviceDeleted;
import com.airlock.iam.airlock2fa.api.domain.model.Airlock2FADeviceInCooldownUsed;
import com.airlock.iam.authentication.api.domain.model.event.AuthenticationFlowSuccessfullyCompleted;
import com.airlock.iam.base.api.domain.model.event.DomainEvent;
import com.airlock.iam.base.api.domain.model.event.source.EventSource;
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.CrontoDeviceActivated;
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.DeviceTokenRegistered;
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.LoginFromNewDeviceEvent;
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.PasswordChanged;
import com.airlock.iam.common.api.domain.model.event.UserCreated;
import com.airlock.iam.common.api.domain.model.event.UserLocked;
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.fido.api.domain.model.event.FidoCredentialDeleted;
import com.airlock.iam.fido.api.domain.model.event.FidoCredentialRegistered;
import com.airlock.iam.flow.api.domain.model.event.FlowEventSource;
import com.airlock.iam.flow.domain.model.event.GenericStepResultEvent;
import com.airlock.iam.flow.shared.api.domain.model.valueprovider.ValueMapProvider;
import com.airlock.iam.oauth2.api.domain.model.event.OAuth2UserConsentEvent;
import com.airlock.iam.plugin.api.event.ConfigurationContextEventSource;
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 LoginappEventValuesProvider implements DomainEventValuesProvider {
   private static final List<CommonUserEventValuesProvider.EventValuesProvider<?>> EVENT_SPECIFIC_PROVIDERS = List.of(
      CommonUserEventValuesProvider.provider(Airlock2FADeviceActivated.class, LoginappEventValues.AIRLOCK_2FA_DEVICE_ACTIVATED_VALUES),
      CommonUserEventValuesProvider.provider(Airlock2FADeviceDeleted.class, LoginappEventValues.AIRLOCK_2FA_DEVICE_DELETED_VALUES),
      CommonUserEventValuesProvider.provider(Airlock2FADeviceInCooldownUsed.class, LoginappEventValues.AIRLOCK_2FA_DEVICE_IN_COOLDOWN_USED_VALUES),
      CommonUserEventValuesProvider.provider(AuthenticationFlowSuccessfullyCompleted.class, LoginappEventValues.AUTHENTICATION_SUCCESSFUL_VALUES),
      CommonUserEventValuesProvider.provider(AuthenticationMethodChanged.class, CommonEventValues.AUTHENTICATION_METHOD_CHANGED_VALUES),
      CommonUserEventValuesProvider.provider(DeviceTokenRegistered.class, CommonEventValues.DEVICE_TOKEN_REGISTERED_VALUES),
      CommonUserEventValuesProvider.provider(DeviceTokenDeleted.class, CommonEventValues.DEVICE_TOKEN_DELETED_VALUES),
      CommonUserEventValuesProvider.provider(CrontoDeviceActivated.class, LoginappEventValues.CRONTO_DEVICE_ACTIVATED_VALUES),
      CommonUserEventValuesProvider.provider(CrontoDeviceDeleted.class, CommonEventValues.CRONTO_DEVICE_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(FidoCredentialRegistered.class, LoginappEventValues.FIDO_CREDENTIAL_REGISTERED_VALUES),
      CommonUserEventValuesProvider.provider(FidoCredentialDeleted.class, LoginappEventValues.FIDO_CREDENTIAL_DELETED_VALUES),
      CommonUserEventValuesProvider.provider(LoginFromNewDeviceEvent.class, LoginappEventValues.LOGIN_FROM_NEW_DEVICE_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(OAuth2UserConsentEvent.class, LoginappEventValues.OAUTH2_USER_CONSENT_VALUES),
      CommonUserEventValuesProvider.provider(PasswordChanged.class, LoginappEventValues.PASSWORD_CHANGED_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(UserUnlocked.class, CommonEventValues.USER_UNLOCKED_VALUES),
      CommonUserEventValuesProvider.provider(GenericStepResultEvent.class, GenericStepResultEventValuesProvider::provideValues)
   );
   private final Provider<ValueMapProvider> configuredValueMapProviders;

   @Inject
   public LoginappEventValuesProvider(Provider<ValueMapProvider> configuredValueMapProviders) {
      this.configuredValueMapProviders = configuredValueMapProviders;
   }

   @Override
   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<>(((ValueMapProvider)this.configuredValueMapProviders.get()).provideValueMap());
      EventSource source = event.source();
      if (source instanceof ConfigurationContextEventSource contextSource) {
         values.put("event.source.configurationContext", contextSource.configurationContext().toString());
      }

      if (source instanceof FlowEventSource flowSource) {
         if (flowSource.stepId().isPresent()) {
            values.put("event.source.stepId", flowSource.stepId().get().toString());
         }

         if (flowSource.applicationId().isPresent()) {
            values.put("event.source.applicationId", flowSource.applicationId().get().toString());
         }

         values.put("event.source.flowId", flowSource.flowId().getFlowId());
      }

      return values;
   }
}
