package com.r35157.jupiterperpsalarm.impl.ref;

import com.r35157.jupiterperpsalarm.AlarmSeverity;

import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Objects;

public final class PushoverAlarmAction implements ConfiguredAlarmAction {

    public PushoverAlarmAction(
            Path configurationDirectory,
            AlarmVariableResolver variableResolver
    ) throws IOException {
        Objects.requireNonNull(configurationDirectory, "configurationDirectory");
        this.variableResolver = Objects.requireNonNull(variableResolver, "variableResolver");
        configuration = PushoverAlarmActionConfigurationParser.parse(
                configurationDirectory.resolve(getConfigurationFileName()),
                variableResolver
        );
    }

    @Override
    public String getConfigurationFileName() {
        return "alarmaction_Pushover.conf";
    }

    @Override
    public void trigger(OraclePrice price, ResolvedPriceAlarm alarm) {
        PushoverAlarmActionConfiguration.Notification notification =
                configuration.notifications().get(alarm.id());
        if (notification == null) {
            return;
        }

        String title = "Jupiter Perps " + price.asset() + " alarm";
        String message = createMessage(
                price,
                alarm,
                notification.severity(),
                variableResolver.resolve(notification.note())
        );

        String body = form("token", configuration.applicationToken()) + "&" +
                form("user", configuration.userKey()) + "&" +
                form("title", title) + "&" +
                form("message", message) + "&" +
                createPushoverSeverityParameters(notification.severity());

        HttpRequest request = HttpRequest.newBuilder(PUSHOVER_URI)
                .timeout(Duration.ofSeconds(15))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .header("User-Agent", "jupiter-perps-price-alarm/1.1")
                .POST(HttpRequest.BodyPublishers.ofString(body))
                .build();

        httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
                .whenComplete((response, error) -> {
                    if (error != null) {
                        System.err.println("Pushover failed: " + error.getMessage());
                        return;
                    }
                    if (response.statusCode() != 200 || !response.body().contains("\"status\":1")) {
                        System.err.printf(
                                "Pushover rejected the alarm: HTTP %d: %s%n",
                                response.statusCode(),
                                response.body()
                        );
                    } else {
                        System.out.println("Pushover alarm sent: " + notification.severity());
                    }
                });
    }

    private static String form(String name, String value) {
        return URLEncoder.encode(name, StandardCharsets.UTF_8) + "=" +
                URLEncoder.encode(value, StandardCharsets.UTF_8);
    }

    private static String createPushoverSeverityParameters(AlarmSeverity severity) {
        return switch (severity) {
            case EMERGENCY -> "priority=2&retry=30&expire=10800&sound=persistent";
            case CRITICAL -> "priority=1&sound=spacealarm";
            case WARN -> "priority=0&sound=siren";
            case INFO -> "priority=0";
            case SILENT -> "priority=-1";
            case GHOST -> "priority=-2";
        };
    }

    private static String createMessage(
            OraclePrice price,
            ResolvedPriceAlarm alarm,
            AlarmSeverity severity,
            String note
    ) {
        return String.format(
                "%d - %s: %s%n%n%s is %s USD.%nCondition: %s USD.%nOracle time: %s.%nSlot: %d.",
                alarm.id(),
                severity,
                note,
                price.asset(),
                price.priceUsd().toPlainString(),
                alarm.condition().expression(),
                price.oracleTime(),
                price.slot()
        );
    }

    private final HttpClient httpClient = HttpClient.newHttpClient();
    private final PushoverAlarmActionConfiguration configuration;
    private final AlarmVariableResolver variableResolver;

    private static final URI PUSHOVER_URI =
            URI.create("https://api.pushover.net/1/messages.json");
}
