package su.xserver.iikocon.test;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.ext.web.codec.BodyCodec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;

public class ProxyVerticlev2 extends AbstractVerticle {

  private static final Logger log = LoggerFactory.getLogger(ProxyVerticlev2.class);
  private WebClient webClient;

  @Override
  public void start(Promise<Void> startPromise) {
    webClient = WebClient.create(vertx, new WebClientOptions()
      .setSsl(true)
      .setTrustAll(true)
      .setVerifyHost(false));

    Router router = Router.router(vertx);
    router.get("/").handler(this::handleGet);

    int port = 80;
    vertx.createHttpServer()
      .requestHandler(router)
      .listen(port).onComplete(http -> {
        if (http.succeeded()) {
          log.info("Proxy server started on port {}", port);
          startPromise.complete();
        } else {
          startPromise.fail(http.cause());
        }
      });
  }

  private void handleGet(RoutingContext ctx) {
    String server = "folk-amber-co.iiko.it";
    String password = "4444";
    String login = "4444";
    String reportType = "DELIVERIES";

    String signature = sha1(password);
    String authUrl = "https://" + server + ":443/resto/api/auth?login=" + login + "&pass=" + signature;
    webClient.getAbs(authUrl)
      .as(BodyCodec.string())
      .send()
      .onSuccess(authResp -> {
        if (authResp.statusCode() != 200) {
          fail(ctx, authResp.statusCode(), "Authentication failed: " + authResp.statusMessage());
          return;
        }
        String token = authResp.body();
        String dataUrl = "https://" + server + "/resto/api/v2/reports/olap/columns" +
            "?key=" + token + "&reportType=" + reportType;
        log.info("URL: {}", dataUrl);
        webClient.getAbs(dataUrl)
          .as(BodyCodec.jsonObject())
          .send()
          .onSuccess(dataResp -> {
            // logout (fire and forget)
            webClient.getAbs("https://" + server + ":443/resto/api/logout?key=" + token)
              .send()
              .onFailure(err -> log.error("Logout failed: {}", err.getMessage()));
            if (dataResp.statusCode() == 200) {
              JsonObject responseBody = dataResp.body();
              log.info(dataResp.headers().toString());
              Object data = responseBody.getValue("data");
              if (data == null) {
                ctx.response().setStatusCode(200).end(responseBody.encode());
              } else {
                // data может быть массивом, объектом или другим типом
                ctx.response().setStatusCode(200).end(Json.encode(data));
              }
            } else {
              fail(ctx, dataResp.statusCode(), "External API error: " + dataResp.statusMessage());
            }
          })
          .onFailure(err -> fail(ctx, 500, "Data request failed: " + err.getMessage()));
      })
      .onFailure(err -> fail(ctx, 500, "Auth request failed: " + err.getMessage()));
  }

  private String sha1(String input) {
    try {
      MessageDigest md = MessageDigest.getInstance("SHA-1");
      byte[] digest = md.digest(input.getBytes());
      return HexFormat.of().formatHex(digest).toLowerCase();
    } catch (NoSuchAlgorithmException e) {
      throw new RuntimeException(e);
    }
  }

  private void fail(RoutingContext ctx, int status, String message) {
    log.info("Error: {}", message);
    ctx.response().setStatusCode(status).end(new JsonObject().put("error", message).encode());
  }
}
