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

import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import com.airlock.iam.common.domain.service.state.StateRepositoryKey;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
import lombok.NonNull;

public record ReentrantLockResult(
   boolean lockAcquired, boolean lockAlreadyOwned, @NonNull Optional<String> owningLockId, Collection<StateRepositoryKey> keysForWhichLocksWereAcquired
) implements RetryableOperation {
   @SuppressFBWarnings(justification = "generated code")
   public ReentrantLockResult {
      if (owningLockId == null) {
         throw new NullPointerException("owningLockId is marked non-null but is null");
      }
   }

   public static ReentrantLockResult alreadyOwnedLock() {
      return new ReentrantLockResult(false, true, Optional.empty(), Set.of());
   }

   public static ReentrantLockResult acquiredLock(StateRepositoryKey... keys) {
      return acquiredLock(Set.of(keys));
   }

   public static ReentrantLockResult acquiredLock(Collection<StateRepositoryKey> keys) {
      ViolationException.checkNotEmpty(keys, "Must acquire lock for at least one key.");
      return new ReentrantLockResult(true, false, Optional.empty(), keys);
   }

   public static ReentrantLockResult lockedBySomeoneElse(String lockId) {
      return new ReentrantLockResult(false, false, Optional.of(lockId), Set.of());
   }

   public boolean isLockedByAnotherOwner() {
      return !this.lockAlreadyOwned && !this.lockAcquired;
   }

   @Override
   public boolean shouldRetry() {
      return this.isLockedByAnotherOwner();
   }
}
