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 JupiterPerpsPositionIncreaseAlarmActionConfigurationParser {
    public static JupiterPerpsPositionIncreaseAlarmActionConfiguration 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, JupiterPerpsPositionIncreaseAlarmActionConfiguration.PositionIncrease>
                positionIncreases = new LinkedHashMap<>();
        ΩUSDCAmountΩ reserveUsdcLimit = 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_USDC_LIMIT")) {
                    requireColumnCount(columns, 2, "RESERVE_USDC_LIMIT value");
                    if (reserveUsdcLimit != null) {
                        throw new IllegalArgumentException(
                                "Duplicate RESERVE_USDC_LIMIT"
                        );
                    }
                    reserveUsdcLimit = new ΩUSDCAmountΩ(
                            variableResolver.resolve(columns[1])
                    );
                } else {
                    parsePositionIncrease(
                            columns,
                            positionIncreases,
                            variableResolver
                    );
                }
            } catch (RuntimeException exception) {
                throw new IllegalArgumentException(
                        path + ":" + lineNumber + ": " + exception.getMessage(),
                        exception
                );
            }
        }

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

        return new JupiterPerpsPositionIncreaseAlarmActionConfiguration(
                reserveUsdcLimit,
                positionIncreases
        );
    }

    private static void parsePositionIncrease(
            String[] columns,
            Map<Integer, JupiterPerpsPositionIncreaseAlarmActionConfiguration.PositionIncrease>
                    positionIncreases,
            AlarmVariableResolver variableResolver
    ) {
        requireColumnCount(
                columns,
                6,
                "alarm id, asset, direction, collateral, size delta, and maximum slippage"
        );

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

        JupiterPerpsPositionIncreaseAlarmActionConfiguration.PositionIncrease positionIncrease =
                new JupiterPerpsPositionIncreaseAlarmActionConfiguration.PositionIncrease(
                        columns[1],
                        columns[2],
                        columns[3],
                        columns[4],
                        columns[5]
                );

        positionIncrease.resolve(variableResolver);
        positionIncreases.put(alarmId, positionIncrease);
    }

    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 JupiterPerpsPositionIncreaseAlarmActionConfigurationParser() {
    }
}
