package com.airlock.iam.flow.shared.domain.service.airlock2fa;

import com.airlock.iam.airlock2fa.api.domain.model.Airlock2FADeviceId;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAAuthTokenId;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAAuthTokenIdCoder;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAFactor;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAFactorSet;
import com.airlock.iam.factor.domain.service.airlock2fa.Airlock2FACooldownInformationServiceImpl;
import com.airlock.iam.flow.api.domain.model.session.FlowAttributeRepository;
import com.airlock.iam.flow.shared.api.domain.service.FlowAttributeService;
import com.airlock.iam.flow.shared.domain.model.airlock2fa.Airlock2FAAuthDeviceAttribute;
import com.airlock.iam.flow.shared.domain.model.attributes.AuthTokenIdFlowSessionAttribute;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;

public final class Airlock2FAFlowSessionAttributesServiceImpl implements Airlock2FAFlowSessionAttributesService {
   private static final ELogger LOG = ELoggerFactory.getLogger(Airlock2FAFlowSessionAttributesServiceImpl.class);
   private final Provider<Airlock2FAAuthTokenIdCoder> coder;
   private final Provider<FlowAttributeRepository> flowAttributes;
   private final Provider<FlowAttributeService> attributeService;

   @Inject
   public Airlock2FAFlowSessionAttributesServiceImpl(
      Provider<Airlock2FAAuthTokenIdCoder> coder, Provider<FlowAttributeRepository> flowAttributes, Provider<FlowAttributeService> attributeService
   ) {
      this.coder = coder;
      this.flowAttributes = flowAttributes;
      this.attributeService = attributeService;
   }

   @Override
   public void saveAuthTokenId(Airlock2FAFactor factor, Airlock2FADeviceId deviceId, Airlock2FAFactorSet allowedFactors) {
      Airlock2FAAuthTokenId authTokenId = new Airlock2FAAuthTokenId(factor, deviceId, allowedFactors);
      String encoded = ((Airlock2FAAuthTokenIdCoder)this.coder.get()).encode(authTokenId);
      ((FlowAttributeRepository)this.flowAttributes.get()).putOrMergeAttribute(AuthTokenIdFlowSessionAttribute.authTokenIdFlowSessionAttribute(encoded));
      LOG.debug("Saved Airlock 2FA used factor and device '%s' in flow attribute '%s' as '%s'".formatted(authTokenId, "authTokenIdKey", encoded));
   }

   @Override
   public void saveAuthDevice(
      Airlock2FADeviceId deviceId,
      Airlock2FACooldownInformationServiceImpl.Airlock2FAAuthDeviceCooldownStatus cooldownStatus,
      Optional<Instant> cooldownEnds,
      Optional<Duration> cooldownPeriod
   ) {
      ((FlowAttributeRepository)this.flowAttributes.get()).putOrMergeAttribute(new Airlock2FAAuthDeviceAttribute(deviceId, cooldownStatus, cooldownEnds));
   }

   @Override
   public Optional<Airlock2FAAuthDeviceAttribute> loadAuthDevice() {
      return ((FlowAttributeService)this.attributeService.get()).findAttribute(Airlock2FAAuthDeviceAttribute.class);
   }

   @Override
   public Optional<Airlock2FAAuthTokenId> loadAuthTokenId() {
      return ((FlowAttributeService)this.attributeService.get())
         .findAttribute(AuthTokenIdFlowSessionAttribute.class)
         .map(AuthTokenIdFlowSessionAttribute::getAuthTokenId)
         .flatMap(authTokenIdString -> ((Airlock2FAAuthTokenIdCoder)this.coder.get()).decode(authTokenIdString));
   }
}
