package com.r35157.jupiterperpsalarm.impl.ref;

import com.r35157.libs.jupiter.perps.JupiterPerpsPositionDirection;

import java.math.BigDecimal;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

public record JupiterPerpsPositionIncreaseAlarmActionConfiguration(
        ΩUSDCAmountΩ reserveUsdcLimit,
        Map<Integer, PositionIncrease> positionIncreases
) {
    public JupiterPerpsPositionIncreaseAlarmActionConfiguration {
        Objects.requireNonNull(reserveUsdcLimit, "reserveUsdcLimit");
        positionIncreases = Map.copyOf(positionIncreases);

        if (reserveUsdcLimit.signum() < 0) {
            throw new IllegalArgumentException(
                    "USDC reserve limit cannot be negative: " + reserveUsdcLimit
            );
        }
    }

    public record PositionIncrease(
            String assetExpression,
            String directionExpression,
            String collateralUsdExpression,
            String sizeUsdDeltaExpression,
            String maxSlippageBpsExpression
    ) {
        public PositionIncrease {
            requireNonBlank(assetExpression, "asset");
            requireNonBlank(directionExpression, "direction");
            requireNonBlank(collateralUsdExpression, "collateral");
            requireNonBlank(sizeUsdDeltaExpression, "position size delta");
            requireNonBlank(maxSlippageBpsExpression, "maximum slippage");
        }

        public ResolvedPositionIncrease resolve(AlarmVariableResolver variableResolver) {
            Objects.requireNonNull(variableResolver, "variableResolver");

            return new ResolvedPositionIncrease(
                    JupiterPerpsAsset.valueOf(
                            variableResolver.resolve(assetExpression).toUpperCase(Locale.ROOT)
                    ),
                    JupiterPerpsPositionDirection.valueOf(
                            variableResolver.resolve(directionExpression)
                                    .toUpperCase(Locale.ROOT)
                    ),
                    new ΩUSDCAmountΩ(variableResolver.resolve(collateralUsdExpression)),
                    new ΩUSDCAmountΩ(variableResolver.resolve(sizeUsdDeltaExpression)),
                    Integer.parseInt(variableResolver.resolve(maxSlippageBpsExpression))
            );
        }

        private static void requireNonBlank(String value, String fieldName) {
            Objects.requireNonNull(value, fieldName);
            if (value.isBlank()) {
                throw new IllegalArgumentException(fieldName + " cannot be blank");
            }
        }
    }

    public record ResolvedPositionIncrease(
            JupiterPerpsAsset asset,
            JupiterPerpsPositionDirection direction,
            ΩUSDCAmountΩ collateralUsd,
            ΩUSDCAmountΩ sizeUsdDelta,
            int maxSlippageBps
    ) {
        public ResolvedPositionIncrease {
            Objects.requireNonNull(asset, "asset");
            Objects.requireNonNull(direction, "direction");
            Objects.requireNonNull(collateralUsd, "collateralUsd");
            Objects.requireNonNull(sizeUsdDelta, "sizeUsdDelta");

            if (collateralUsd.signum() <= 0) {
                throw new IllegalArgumentException(
                        "Collateral must be greater than zero: " + collateralUsd
                );
            }
            if (sizeUsdDelta.signum() < 0) {
                throw new IllegalArgumentException(
                        "Position size delta cannot be negative: " + sizeUsdDelta
                );
            }
            if (maxSlippageBps < 0 || maxSlippageBps > 10_000) {
                throw new IllegalArgumentException(
                        "Maximum slippage must be between 0 and 10000 basis points: "
                                + maxSlippageBps
                );
            }
        }
    }
}
