package com.airlock.iam.login.infrastructure.captcha;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.validation.ValidationResult;
import com.airlock.iam.base.api.domain.model.validation.ValidatorError;
import com.airlock.iam.common.infrastructure.restclient.JerseyRestClient;
import com.airlock.iam.common.infrastructure.restclient.RestRequest;
import com.airlock.iam.flow.shared.api.domain.model.captcha.CaptchaValidationError;
import com.airlock.iam.flow.shared.domain.model.captcha.CaptchaValidationResponse;
import com.airlock.iam.flow.shared.domain.service.captcha.CaptchaValidationService;
import jakarta.ws.rs.client.Entity;
import java.util.ArrayList;
import java.util.List;
import org.glassfish.jersey.internal.util.collection.MultivaluedStringMap;

public class CaptchaValidationServiceImpl implements CaptchaValidationService {
   private final JerseyRestClient restClient;
   private final String path;

   public CaptchaValidationServiceImpl(JerseyRestClient restClient, String path) {
      this.path = path;
      this.restClient = restClient;
   }

   @Override
   public ValidationResult validateToken(String secretKey, String answer) {
      CaptchaValidationResponse validationResponse = this.restClient
         .read(this.createRequest(secretKey, answer), response -> response.readEntity(CaptchaValidationResponse.class));
      return this.interpretResult(validationResponse);
   }

   private ValidationResult interpretResult(CaptchaValidationResponse response) {
      if (response.isSuccess()) {
         return ValidationResult.valid();
      }

      List<ValidatorError> errors = new ArrayList<>();

      for (String error : response.getErrorCodes()) {
         switch (error) {
            case "missing-input-response":
            case "invalid-input-response":
            case "not-using-dummy-passcode":
            case "timeout-or-duplicate":
            case "invalid-or-already-seen-response":
               errors.add(ValidatorError.validatorError(CaptchaValidationError.SOLUTION_INVALID));
               break;
            case "missing-input-secret":
            case "invalid-input-secret":
            case "not-using-dummy-secret":
               throw new FailureException("CAPTCHA could not be verified, because the secret was not present or not valid: " + error);
            default:
               throw new FailureException("CAPTCHA could not be verified: " + error);
         }
      }

      return errors.isEmpty() ? ValidationResult.valid() : ValidationResult.invalid(errors);
   }

   private RestRequest createRequest(String secretKey, String answer) {
      MultivaluedStringMap body = new MultivaluedStringMap();
      body.add("secret", secretKey);
      body.add("response", answer);
      return RestRequest.builder().method(RestRequest.RestRequestMethod.POST).path(this.path).body(Entity.form(body)).build();
   }
}
