package com.airlock.iam.common.infrastructure.service;

import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.common.api.domain.model.store.user.UserStore;
import com.airlock.iam.common.api.domain.model.user.PersistentUser;
import com.airlock.iam.common.api.domain.model.user.UserIdentity;
import com.airlock.iam.common.domain.model.principal.UserPrincipal;
import com.airlock.iam.common.domain.model.principal.UserPrincipalImpl;
import com.airlock.iam.common.domain.service.principal.UserPrincipalService;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Optional;

public class PersistentUserPrincipalService implements UserPrincipalService, InternalUserPrincipalService {
   private final Provider<UserStore> userStore;
   private final Provider<UserPrincipal> userPrincipal;

   @Inject
   public PersistentUserPrincipalService(Provider<UserStore> userStore, Provider<UserPrincipal> userPrincipal) {
      this.userStore = userStore;
      this.userPrincipal = userPrincipal;
   }

   @Override
   public UserPrincipal initializePrincipal(UserIdentity userIdentity) {
      Optional<PersistentUser> user = this.loadOptionalUser(userIdentity);
      UserPrincipalImpl principal = (UserPrincipalImpl)this.userPrincipal.get();
      UserIdentity reloadedUserIdentity = getPersistentUserIdentity(userIdentity, user);
      principal.initialize(reloadedUserIdentity, user);
      return principal;
   }

   @Override
   public void internalInitialize(UserIdentity userIdentity, UserPrincipalImpl principal) {
      Optional<PersistentUser> user = this.loadOptionalUser(userIdentity);
      principal.initialize(getPersistentUserIdentity(userIdentity, user), user);
   }

   private static UserIdentity getPersistentUserIdentity(UserIdentity userIdentity, Optional<PersistentUser> user) {
      UserId finalUserId = user.map(PersistentUser::getName).map(UserId::userId).orElse(userIdentity.id());
      return new UserIdentity(finalUserId, userIdentity.providedUsername());
   }

   private Optional<PersistentUser> loadOptionalUser(UserIdentity userIdentity) {
      return ((UserStore)this.userStore.get()).findByIdentity(userIdentity.id());
   }

   @Override
   public void savePrincipal() {
      if (((UserPrincipal)this.userPrincipal.get()).userOptional().isPresent()) {
         ((UserStore)this.userStore.get()).update(((UserPrincipal)this.userPrincipal.get()).user());
      }
   }

   @Override
   public void reloadPrincipal() {
      if (((UserPrincipal)this.userPrincipal.get()).userOptional().isPresent()) {
         ((UserStore)this.userStore.get())
            .findByIdentity(((UserPrincipal)this.userPrincipal.get()).getId())
            .ifPresent(user -> ((UserPrincipalImpl)this.userPrincipal.get()).update(user));
      }
   }
}
