package com.r35157.jupiterperpsalarm.impl.ref;

import com.r35157.libs.configuration.ConfigurationFormatVersionValidator;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

public final class JupiterPerpsPositionDecreaseAlarmActionConfigurationParser {
    public static JupiterPerpsPositionDecreaseAlarmActionConfiguration parse(
            Path path,
            AlarmVariableResolver variableResolver
    ) throws IOException {
        Objects.requireNonNull(variableResolver, "variableResolver");
        List<String> lines = Files.readAllLines(path);
        int formatVersionLineIndex = ConfigurationFormatVersionValidator.validate(
                path,
                lines,
                SUPPORTED_FORMAT_VERSION
        );
        Map<Integer, JupiterPerpsPositionDecreaseAlarmActionConfiguration.PositionDecrease>
                positionDecreases = new LinkedHashMap<>();
        ΩUSDCAmountΩ reservePositionSizeUsdLimit = null;

        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 {
                String[] columns = line.split("\\s+");
                String firstColumn = columns[0].toUpperCase(Locale.ROOT);

                if (firstColumn.equals("RESERVE_POSITION_SIZE_USD_LIMIT")) {
                    requireColumnCount(
                            columns,
                            2,
                            "RESERVE_POSITION_SIZE_USD_LIMIT value"
                    );
                    if (reservePositionSizeUsdLimit != null) {
                        throw new IllegalArgumentException(
                                "Duplicate RESERVE_POSITION_SIZE_USD_LIMIT"
                        );
                    }
                    reservePositionSizeUsdLimit = new ΩUSDCAmountΩ(
                            variableResolver.resolve(columns[1])
                    );
                } else {
                    parsePositionDecrease(
                            columns,
                            positionDecreases,
                            variableResolver
                    );
                }
            } catch (RuntimeException exception) {
                throw new IllegalArgumentException(
                        path + ":" + lineNumber + ": "
                                + exception.getMessage(),
                        exception
                );
            }
        }

        if (reservePositionSizeUsdLimit == null) {
            throw new IllegalArgumentException(
                    "Missing RESERVE_POSITION_SIZE_USD_LIMIT in " + path
            );
        }

        return new JupiterPerpsPositionDecreaseAlarmActionConfiguration(
                reservePositionSizeUsdLimit,
                positionDecreases
        );
    }

    private static void parsePositionDecrease(
            String[] columns,
            Map<Integer, JupiterPerpsPositionDecreaseAlarmActionConfiguration.PositionDecrease>
                    positionDecreases,
            AlarmVariableResolver variableResolver
    ) {
        requireColumnCount(
                columns,
                6,
                "alarm id, asset, direction, receive token, "
                        + "size delta, and maximum slippage"
        );

        int alarmId = Integer.parseInt(columns[0]);
        if (positionDecreases.containsKey(alarmId)) {
            throw new IllegalArgumentException(
                    "Duplicate alarm id: " + alarmId
            );
        }

        JupiterPerpsPositionDecreaseAlarmActionConfiguration.PositionDecrease
                positionDecrease =
                new JupiterPerpsPositionDecreaseAlarmActionConfiguration.PositionDecrease(
                        columns[1],
                        columns[2],
                        columns[3],
                        columns[4],
                        columns[5]
                );

        positionDecrease.resolve(variableResolver);
        positionDecreases.put(alarmId, positionDecrease);
    }

    private static void requireColumnCount(
            String[] columns,
            int expected,
            String expectedColumns
    ) {
        if (columns.length != expected) {
            throw new IllegalArgumentException(
                    "Expected " + expectedColumns + ", but found "
                            + columns.length + " column(s)"
            );
        }
    }

    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 = 2;

    private JupiterPerpsPositionDecreaseAlarmActionConfigurationParser() {
    }
}
