package com.r35157.jupiterperpsalarm.impl.ref;

import com.r35157.libs.configuration.ConfigurationFormatVersionValidator;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

public final class ConsoleAlarmAction implements ConfiguredAlarmAction {
    public ConsoleAlarmAction(Path configurationDirectory) throws IOException {
        Objects.requireNonNull(configurationDirectory, "configurationDirectory");
        alarmIds = parseAlarmIds(
                configurationDirectory.resolve(getConfigurationFileName())
        );
    }

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

    @Override
    public void trigger(OraclePrice price, ResolvedPriceAlarm alarm) {
        if (!alarmIds.contains(alarm.id())) {
            return;
        }

        System.err.println();
        System.err.println("============================================================");
        System.err.printf(
                "ALARM_%d: %s is %s USD; condition %s USD%n",
                alarm.id(),
                price.asset(),
                price.priceUsd().toPlainString(),
                alarm.condition().expression()
        );
        System.err.printf(
                "Trigger: %s, oracle time: %s, slot: %d, source: %s%n",
                alarm.trigger(),
                price.oracleTime(),
                price.slot(),
                price.source()
        );
        System.err.println("============================================================");
        System.err.println();
    }

    private static Set<Integer> parseAlarmIds(Path path) throws IOException {
        List<String> lines = Files.readAllLines(path);
        int formatVersionLineIndex = ConfigurationFormatVersionValidator.validate(
                path,
                lines,
                SUPPORTED_FORMAT_VERSION
        );
        Set<Integer> result = new LinkedHashSet<>();

        for (int lineNumber = 1; lineNumber <= lines.size(); lineNumber++) {
            if (lineNumber - 1 == formatVersionLineIndex) {
                continue;
            }

            String line = removeComment(lines.get(lineNumber - 1)).trim();
            if (line.isEmpty()) {
                continue;
            }

            try {
                if (line.chars().anyMatch(Character::isWhitespace)) {
                    throw new IllegalArgumentException(
                            "Expected one alarm id, but found: " + line
                    );
                }

                int alarmId = Integer.parseInt(line);
                if (!result.add(alarmId)) {
                    throw new IllegalArgumentException(
                            "Duplicate alarm id: " + alarmId
                    );
                }
            } catch (RuntimeException exception) {
                throw new IllegalArgumentException(
                        path + ":" + lineNumber + ": " + exception.getMessage(),
                        exception
                );
            }
        }

        return Set.copyOf(result);
    }

    private static String removeComment(String line) {
        int commentStart = line.indexOf('#');
        return commentStart < 0 ? line : line.substring(0, commentStart);
    }

    private static final int SUPPORTED_FORMAT_VERSION = 1;

    private final Set<Integer> alarmIds;
}
