package com.airlock.iam.flow.shared.infrastructure.service.newdevice;

import com.airlock.iam.base.misc.result.Result;
import com.airlock.iam.core.misc.util.ServletUtils;
import com.airlock.iam.flow.shared.domain.model.newdevice.LoginFromNewDeviceKnownUsers;
import com.airlock.iam.flow.shared.domain.model.newdevice.LoginFromNewDeviceSettings;
import com.airlock.iam.flow.shared.domain.service.newdevice.LoginFromNewDeviceRequest;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Optional;

public final class LoginFromNewDeviceRequestImpl implements LoginFromNewDeviceRequest {
   private final Provider<HttpServletRequest> request;
   private final Provider<LoginFromNewDeviceSettings> settings;
   private final Provider<LoginFromNewDeviceKnownUsersSerializer> serializer;

   @Inject
   public LoginFromNewDeviceRequestImpl(
      Provider<HttpServletRequest> request, Provider<LoginFromNewDeviceSettings> settings, Provider<LoginFromNewDeviceKnownUsersSerializer> serializer
   ) {
      this.request = request;
      this.settings = settings;
      this.serializer = serializer;
   }

   @Override
   public Result<LoginFromNewDeviceKnownUsers, String> getKnownUsers() {
      return Optional.ofNullable(
            ServletUtils.getCookie((HttpServletRequest)this.request.get(), ((LoginFromNewDeviceSettings)this.settings.get()).cookieName().name())
         )
         .<String>map(Cookie::getValue)
         .map(jwt -> ((LoginFromNewDeviceKnownUsersSerializer)this.serializer.get()).deserialize(jwt))
         .map(result -> mapParsingFailureToString((Result<LoginFromNewDeviceKnownUsers, LoginFromNewDeviceParsingFailure>)result))
         .orElse(Result.result(LoginFromNewDeviceKnownUsers.empty()));
   }

   private static Result<LoginFromNewDeviceKnownUsers, String> mapParsingFailureToString(
      Result<LoginFromNewDeviceKnownUsers, LoginFromNewDeviceParsingFailure> result
   ) {
      return result.isFailure() ? Result.failure(result.getFailure().getMessage()) : Result.result(result.get());
   }
}
