package com.airlock.iam.common.domain.model.user;

import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.base.misc.adapt.AdaptFrom;
import com.airlock.iam.base.misc.adapt.AdaptTo;
import com.airlock.iam.common.api.domain.model.locking.LockReason;
import com.airlock.iam.common.api.domain.model.user.PersistentUser;
import com.airlock.iam.common.domain.model.locking.LockReasons;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
import java.util.Optional;

public class LockableImpl implements Lockable {
   private final PersistentUser user;
   private boolean stateUpdated;

   public LockableImpl(PersistentUser user) {
      this.user = user;
   }

   @AdaptFrom
   public static LockableImpl fromUser(PersistentUser user) {
      return new LockableImpl(user);
   }

   @AdaptTo
   public PersistentUser toUser() {
      return this.user;
   }

   @Override
   public String id() {
      return this.user.getName();
   }

   @Override
   public void lock(LockReason reason) {
      this.lock(reason.getResourceKey());
   }

   @Override
   public void lock(String reason) {
      this.user.setLocked();
      this.user.setLockReason(reason);
      this.user.setLockDate(new Date());
      this.stateUpdated = true;
   }

   @Override
   public void unlock() {
      this.user.setLocked(false);
      this.user.setLockDate(null);
      this.user.setLockReason(null);
      this.user.resetFailedLogins();
      this.user.getAllFailedLogins().resetAllFailedLoginCounters();
      this.stateUpdated = true;
   }

   @Override
   public UserLockState lockState() {
      return UserLockState.builder()
         .userId(UserId.userId(this.user.getName()))
         .reason(Optional.ofNullable(this.user.getLockReason()).map(LockReasons::toLockReason))
         .locked(this.user.isLocked())
         .lockDate(this.user.getLockDate())
         .stateUpdated(this.stateUpdated)
         .build();
   }

   @SuppressFBWarnings(justification = "generated code")
   PersistentUser getUser() {
      return this.user;
   }
}
