package de.unikoblenz.fgbks.api;

import static de.unikoblenz.fgbks.core.dmn.verification.metrics.DmnVerificationMetricsService.PUBLIC_TOKEN;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;

import de.unikoblenz.fgbks.core.dmn.verification.DmnVerificationService;
import de.unikoblenz.fgbks.core.dmn.verification.metrics.DmnVerificationMetricsService;
import de.unikoblenz.fgbks.core.dmn.verification.result.VerifierResultSet;
import de.unikoblenz.fgbks.core.dmn.verification.result.actions.ActionScope;
import de.unikoblenz.fgbks.core.dmn.verification.result.actions.ActionType;
import de.unikoblenz.fgbks.core.dmn.verification.result.actions.FixActionService;
import de.unikoblenz.fgbks.core.dmn.verification.verifier.classification.ClassificationType;
import de.unikoblenz.fgbks.core.dmn.verification.verifier.types.VerificationType;
import java.util.List;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

/**
 * API for the dmn verification service. Provides methods for generating verifications for dmn
 * tables.
 */
@Path("/api/dmn/verification")
public class Verification {

  @Inject protected DmnVerificationService dmnVerificationService;
  @Inject
  protected DmnVerificationMetricsService dmnVerificationMetricsService;
  @Inject
  protected FixActionService fixActionService;

  /**
   * Method to generate all verifications for a dmn with all registered verifiers.
   *
   * @param token the token for the metric statistics
   * @param payload the dmn as XML format as
   * @return a JSON String, which represents a {@link VerifierResultSet}
   */
  @POST
  @Produces(MediaType.APPLICATION_JSON)
  @Consumes(MediaType.TEXT_XML)
  public Response verifyAll(
      @DefaultValue(PUBLIC_TOKEN) @QueryParam("token") String token, String payload) {
    return checkResult(dmnVerificationService.generate(payload, token));
  }

  /**
   * Method to get all registered verification types.
   *
   * @return a list of {@link VerificationType} as a JSON String.
   */
  @GET
  @Path("/types")
  @Produces(MediaType.APPLICATION_JSON)
  public Response verifyType() {
    return Response.accepted(dmnVerificationService.getVerificationTypes()).build();
  }

  /**
   * Method to generate all verifications for a dmn with the given names of {@link
   * VerificationType}. The types are listed in the query param "typeName". Multiple typeNames can
   * be requested.
   *
   * @param token the token for the metric statistics
   * @param typeNames the "typeName"(s) of a {@link VerificationType}
   * @param payload the dmn as XML format as
   * @return a JSON String, which represents a {@link VerifierResultSet}
   */
  @POST
  @Path("/types")
  @Produces(MediaType.APPLICATION_JSON)
  @Consumes(MediaType.TEXT_XML)
  public Response verifyTypes(
      @DefaultValue(PUBLIC_TOKEN) @QueryParam("token") String token,
      @QueryParam("typeName") List<String> typeNames,
      String payload) {
    return checkResult(dmnVerificationService.generateFromTypes(typeNames, payload, token));
  }

  /**
   * Method to get all registered classification types.
   *
   * @return a list of {@link ClassificationType} as a JSON String.
   */
  @GET
  @Path("/classifications")
  @Produces(MediaType.APPLICATION_JSON)
  public Response verifyClassification() {
    return Response.accepted(dmnVerificationService.getVerificationClassificationTypes()).build();
  }

  /**
   * Method to generate all verifications for a dmn with the given name of a {@link
   * ClassificationType}.
   *
   * @param token the token for the metric statistics
   * @param classificationName the name of a {@link ClassificationType}
   * @param payload the dmn as XML format as
   * @return a JSON String, which represents a {@link VerifierResultSet}
   */
  @POST
  @Path("/classifications/{classificationName}")
  @Produces(MediaType.APPLICATION_JSON)
  @Consumes(MediaType.TEXT_XML)
  public Response verifyClassification(
      @DefaultValue(PUBLIC_TOKEN) @QueryParam("token") String token,
      @PathParam("classificationName") String classificationName,
      String payload) {
    return checkResult(
        dmnVerificationService.generateFromClassification(classificationName, payload, token));
  }

  private Response checkResult(VerifierResultSet resultSet) {
    if (resultSet.getAmountOfVerifier() == 0) {
      return Response.status(
          BAD_REQUEST.getStatusCode(),
          "The dmn syntax is not correct. The dmn can not be parsed.")
          .build();
    } else {
      return Response.accepted(resultSet).build();
    }
  }

  /**
   * Method to get all registered classification types.
   *
   * @param token the token for the metric statistics
   * @return a list of {@link ClassificationType} as a JSON String.
   */
  @GET
  @Path("/metrics")
  @Produces(MediaType.APPLICATION_JSON)
  public Response metrics(@DefaultValue(PUBLIC_TOKEN) @QueryParam("token") String token) {
    return Response.accepted(dmnVerificationMetricsService.getMetrics(token)).build();
  }

  /**
   * Method to get a boolean, if the actions are active or inactive
   *
   * @return true, if the actions are active
   */
  @GET
  @Path("/actions/global")
  @Produces(MediaType.TEXT_PLAIN)
  public Response getActionsGlobal() {
    return Response.accepted(fixActionService.isGlobalActive()).build();
  }

  /**
   * Method to set a boolean, if the actions is active or inactive
   *
   * @return true, if the actions are active
   */
  @POST
  @Path("/actions/global/{active}")
  @Produces(MediaType.TEXT_PLAIN)
  public Response setActionsGlobal(@PathParam("active") boolean active) {
    fixActionService.setGlobalActive(active);
    return Response.accepted(fixActionService.isGlobalActive()).build();
  }

  /**
   * Method to get all allowed actions
   *
   * @return a map of allowed actions
   */
  @GET
  @Path("/actions/allowedActions")
  @Produces(MediaType.APPLICATION_JSON)
  public Response getAllowedActions() {
    return Response.accepted(fixActionService.getAllowedActions()).build();
  }

  /**
   * Method to get all action types
   *
   * @return a map of allowed actions
   */
  @GET
  @Path("/actions/actionTypes")
  @Produces(MediaType.APPLICATION_JSON)
  public Response getActionsTypes() {
    return Response.accepted(fixActionService.getActionTypes()).build();
  }

  /**
   * Method to get all action scopes
   *
   * @return a list of actions scopes
   */
  @GET
  @Path("/actions/actionScopes")
  @Produces(MediaType.APPLICATION_JSON)
  public Response getActionsScopes() {
    return Response.accepted(fixActionService.getActionScopes()).build();
  }

  /**
   * Method to set a boolean, if the actions type are active or inactive
   *
   * @return true, if the request was successful
   */
  @POST
  @Path("/actions/allowedActions/{scope}/{type}/{value}")
  @Produces(MediaType.TEXT_PLAIN)
  public Response setAllowedActions(
      @PathParam("scope") String actionScope,
      @PathParam("type") String actionType,
      @PathParam("value") Boolean value) {
    try {
      fixActionService.setValue(
          ActionScope.valueOf(actionScope), ActionType.valueOf(actionType), value);
      return Response.accepted(true).build();
    } catch (Exception e) {
      return Response.accepted(false).build();
    }
  }
}