package cz.senslog.analytics.module;

import cz.senslog.analytics.app.Application;
import cz.senslog.analytics.domain.ThresholdViolationAlert;
import cz.senslog.analytics.module.api.SimpleModule;
import cz.senslog.analytics.server.ws.ContentType;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.*;
import io.vertx.core.json.JsonObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.function.Function;

public final class AlertModule extends SimpleModule {

    private static final Logger logger = LogManager.getLogger(AlertModule.class);

    private HttpClient httpClient;

    private Function<ThresholdViolationAlert, Future<Buffer>> alertHandler;

    private String alertServerMsgPath;

    @Override
    public void configure(Promise<Void> completePromise) {
        JsonObject moduleConfig = config().getJsonObject("modules");

        boolean disabled = moduleConfig.getBoolean("alert.service.disabled");
        if (disabled) {
            this.alertHandler = alert -> {
                logger.info("Alert: {}", alert.message());
                return Future.succeededFuture(Buffer.buffer("Alert service disabled. Logging to console."));
            };
            completePromise.complete(); return;
        }

        HttpClientOptions httpOpts = new HttpClientOptions()
                .setDefaultHost(moduleConfig.getString("alert.service.host"))
                .setDefaultPort(moduleConfig.getInteger("alert.service.port"));

        httpClient = vertx.createHttpClient(httpOpts);
        alertServerMsgPath = moduleConfig.getString("alert.service.path.message");

        logger.info("Connecting to the alert server {} at {}.", httpOpts.getDefaultHost(), httpOpts.getDefaultPort());
        httpClient.request(HttpMethod.GET, moduleConfig.getString("alert.service.path.info"))
                        .compose(req -> req.send().compose(HttpClientResponse::body))
                .onSuccess(info -> {
                    String alertServerInfo = String.join(" | ", info.toJsonObject().stream().map(e -> e.getKey() + ": " + e.getValue()).toList());
                    logger.info("Connected to Alert Server: {}", alertServerInfo);
                    this.alertHandler = this::sendToAlertService;
                    completePromise.complete();
                })
                .onFailure(completePromise::fail);
    }

    private Future<Buffer> sendToAlertService(ThresholdViolationAlert alert) {
        return httpClient.request(HttpMethod.POST, alertServerMsgPath)
                .compose(req -> req.putHeader(HttpHeaders.CONTENT_TYPE, ContentType.JSON.contentType())
                        .send(JsonObject.of(
                                "title",  String.format("[%s] %s", Application.PROJECT_NAME, alert.sourceName()),
                                "message", alert.message()
                        ).encode())
                        .compose(HttpClientResponse::body));
    }

    @Override
    public void run(Promise<Void> completePromise) {
        vertx.eventBus().<ThresholdViolationAlert>consumer(id(), msg -> alertHandler.apply(msg.body())
                            .onSuccess(b -> logger.info(b.toString()))
                            .onFailure(logger::error))
                .completionHandler(ar -> {
                    if (ar.succeeded()) {
                        completePromise.complete();
                    } else {
                        completePromise.fail(ar.cause());
                    }
                });
    }
}