package de.szut.casino.dice;

import de.szut.casino.shared.service.BalanceService;
import de.szut.casino.user.UserEntity;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;

@Service
public class DiceService {
    private static final int MAX_DICE_VALUE = 100;
    private final Random random;
    private final BalanceService balanceService;

    public DiceService(Random random, BalanceService balanceService) {
        this.random = random;
        this.balanceService = balanceService;
    }

    public DiceResult play(UserEntity user, DiceDto diceDto) {
        balanceService.subtractFunds(user, diceDto.getBetAmount());

        int rolledValue = random.nextInt(MAX_DICE_VALUE) + 1;
        BigDecimal rolledValueDecimal = BigDecimal.valueOf(rolledValue);

        BigDecimal targetValue = diceDto.getTargetValue();
        boolean isRollOver = diceDto.isRollOver();

        boolean winConditionMet = isWinConditionMet(rolledValueDecimal, targetValue, isRollOver);

        if (!winConditionMet) {
            return new DiceResult(false, BigDecimal.ZERO, rolledValueDecimal);
        }

        BigDecimal winChance = calculateWinChance(targetValue, isRollOver);
        BigDecimal multiplier = calculateMultiplier(winChance);

        BigDecimal payout = diceDto.getBetAmount().multiply(multiplier);
        balanceService.addFunds(user, payout);

        return new DiceResult(true, payout, rolledValueDecimal);
    }

    private boolean isWinConditionMet(BigDecimal rolledValue, BigDecimal targetValue, boolean isRollOver) {
        if (isRollOver) {
            return rolledValue.compareTo(targetValue) > 0;
        }

        return rolledValue.compareTo(targetValue) < 0;
    }

    private BigDecimal calculateWinChance(BigDecimal targetValue, boolean isRollOver) {
        if (isRollOver) {
            return BigDecimal.valueOf(MAX_DICE_VALUE).subtract(targetValue);
        }

        return targetValue.subtract(BigDecimal.ONE);
    }

    private BigDecimal calculateMultiplier(BigDecimal winChance) {
        if (winChance.compareTo(BigDecimal.ZERO) > 0) {
            return BigDecimal.valueOf(MAX_DICE_VALUE - 1).divide(winChance, 4, RoundingMode.HALF_UP);
        }

        return BigDecimal.ZERO;
    }
}
