package com.airlock.iam.base.infrastructure.validation;

import ch.ergon.restal.jsonapi.document.data.Relationship;
import ch.ergon.restal.jsonapi.document.data.ResourceIdentifier;
import ch.ergon.restal.jsonapi.document.data.Relationship.ToOneRelationship;
import ch.ergon.restal.jsonapi.document.request.RequestDocument;
import com.airlock.iam.base.api.domain.model.validation.GenericError;
import com.airlock.iam.base.api.domain.model.validation.ValidatorError;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public final class RelationshipValidator<T> {
   private final String type;

   public RelationshipValidator.Result validate(RequestDocument<T> requestDocument) {
      RelationshipValidator.Result.ResultBuilder builder = RelationshipValidator.Result.builder();
      if (requestDocument.getData().getRelationships() == null) {
         return builder.error(ValidatorError.validatorError("/data/relationships", GenericError.REQUIRED)).build();
      } else {
         Relationship techClientRelationship = requestDocument.getData().getRelationship(this.type);
         if (!(techClientRelationship instanceof ToOneRelationship)) {
            return builder.error(ValidatorError.validatorError("/data/relationships/" + this.type, GenericError.REQUIRED)).build();
         } else {
            ResourceIdentifier techClientResourceIdentifier = ((ToOneRelationship)techClientRelationship).getData();
            if (techClientResourceIdentifier == null) {
               return builder.error(ValidatorError.validatorError("/data/relationships/" + this.type + "/data", GenericError.REQUIRED)).build();
            } else if (techClientResourceIdentifier.getId() == null) {
               return builder.error(ValidatorError.validatorError("/data/relationships/" + this.type + "/data/id", GenericError.REQUIRED)).build();
            } else {
               return !this.type.equals(techClientResourceIdentifier.getType())
                  ? builder.error(ValidatorError.validatorError("/data/relationships/" + this.type + "/data/type", GenericError.INVALID_VALUE)).build()
                  : builder.resourceIdentifier(techClientResourceIdentifier).build();
            }
         }
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   RelationshipValidator(String type) {
      this.type = type;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static <T> RelationshipValidator.RelationshipValidatorBuilder<T> builder() {
      return new RelationshipValidator.RelationshipValidatorBuilder<>();
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class RelationshipValidatorBuilder<T> {
      @SuppressFBWarnings(justification = "generated code")
      private String type;

      @SuppressFBWarnings(justification = "generated code")
      RelationshipValidatorBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public RelationshipValidator.RelationshipValidatorBuilder<T> type(String type) {
         this.type = type;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RelationshipValidator<T> build() {
         return new RelationshipValidator<>(this.type);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "RelationshipValidator.RelationshipValidatorBuilder(type=" + this.type + ")";
      }
   }

   public static final class Result {
      private final ResourceIdentifier resourceIdentifier;
      private final List<ValidatorError> errors;

      public boolean hasErrors() {
         return !this.errors.isEmpty();
      }

      @SuppressFBWarnings(justification = "generated code")
      Result(ResourceIdentifier resourceIdentifier, List<ValidatorError> errors) {
         this.resourceIdentifier = resourceIdentifier;
         this.errors = errors;
      }

      @SuppressFBWarnings(justification = "generated code")
      public static RelationshipValidator.Result.ResultBuilder builder() {
         return new RelationshipValidator.Result.ResultBuilder();
      }

      @SuppressFBWarnings(justification = "generated code")
      public ResourceIdentifier getResourceIdentifier() {
         return this.resourceIdentifier;
      }

      @SuppressFBWarnings(justification = "generated code")
      public List<ValidatorError> getErrors() {
         return this.errors;
      }

      @SuppressFBWarnings(justification = "generated code")
      public static class ResultBuilder {
         @SuppressFBWarnings(justification = "generated code")
         private ResourceIdentifier resourceIdentifier;
         @SuppressFBWarnings(justification = "generated code")
         private ArrayList<ValidatorError> errors;

         @SuppressFBWarnings(justification = "generated code")
         ResultBuilder() {
         }

         @SuppressFBWarnings(justification = "generated code")
         public RelationshipValidator.Result.ResultBuilder resourceIdentifier(ResourceIdentifier resourceIdentifier) {
            this.resourceIdentifier = resourceIdentifier;
            return this;
         }

         @SuppressFBWarnings(justification = "generated code")
         public RelationshipValidator.Result.ResultBuilder error(ValidatorError error) {
            if (this.errors == null) {
               this.errors = new ArrayList<>();
            }

            this.errors.add(error);
            return this;
         }

         @SuppressFBWarnings(justification = "generated code")
         public RelationshipValidator.Result.ResultBuilder errors(Collection<? extends ValidatorError> errors) {
            if (errors == null) {
               throw new NullPointerException("errors cannot be null");
            }

            if (this.errors == null) {
               this.errors = new ArrayList<>();
            }

            this.errors.addAll(errors);
            return this;
         }

         @SuppressFBWarnings(justification = "generated code")
         public RelationshipValidator.Result.ResultBuilder clearErrors() {
            if (this.errors != null) {
               this.errors.clear();
            }

            return this;
         }

         @SuppressFBWarnings(justification = "generated code")
         public RelationshipValidator.Result build() {
            return new RelationshipValidator.Result(this.resourceIdentifier, switch (this.errors == null ? 0 : this.errors.size()) {
               case 0 -> Collections.emptyList();
               case 1 -> Collections.singletonList((T)((ValidatorError)this.errors.get(0)));
               default -> Collections.unmodifiableList(new ArrayList<>(this.errors));
            });
         }

         @SuppressFBWarnings(justification = "generated code")
         @Override
         public String toString() {
            return "RelationshipValidator.Result.ResultBuilder(resourceIdentifier=" + this.resourceIdentifier + ", errors=" + this.errors + ")";
         }
      }
   }
}
