<?php
declare(strict_types=1);

const SLOT_JP_TIERS = ['mini', 'minor', 'major', 'grand'];

const SLOT_JP_SEEDS = [
    'mini' => 120,
    'minor' => 650,
    'major' => 3200,
    'grand' => 18000,
];

/** Bet fraction added to pools (3% total). */
const SLOT_JP_CONTRIB_RATE = 0.03;

const SLOT_JP_CONTRIB_SPLIT = [
    'mini' => 0.35,
    'minor' => 0.30,
    'major' => 0.20,
    'grand' => 0.15,
];

/** Per-spin win chance out of 1_000_000 (before bet scaling). */
const SLOT_JP_ODDS = [
    'mini' => 1200,
    'minor' => 320,
    'major' => 48,
    'grand' => 6,
];

function slot_jackpots_path(): string
{
    return dirname(__DIR__) . '/data/slot_jackpots.json';
}

function slot_jackpots_default_state(): array
{
    return [
        'mini' => SLOT_JP_SEEDS['mini'],
        'minor' => SLOT_JP_SEEDS['minor'],
        'major' => SLOT_JP_SEEDS['major'],
        'grand' => SLOT_JP_SEEDS['grand'],
        'updatedAt' => time(),
    ];
}

function slot_jackpots_read(): array
{
    $path = slot_jackpots_path();
    if (!is_readable($path)) {
        return slot_jackpots_default_state();
    }
    $raw = @file_get_contents($path);
    if ($raw === false || $raw === '') {
        return slot_jackpots_default_state();
    }
    $j = json_decode($raw, true);
    if (!is_array($j)) {
        return slot_jackpots_default_state();
    }
    $out = slot_jackpots_default_state();
    foreach (SLOT_JP_TIERS as $tier) {
        if (isset($j[$tier]) && is_numeric($j[$tier])) {
            $out[$tier] = max((int) SLOT_JP_SEEDS[$tier], (int) $j[$tier]);
        }
    }
    $out['updatedAt'] = isset($j['updatedAt']) ? (int) $j['updatedAt'] : time();

    return $out;
}

function slot_jackpots_write(array $state): void
{
    $path = slot_jackpots_path();
    $dir = dirname($path);
    if (!is_dir($dir)) {
        @mkdir($dir, 0755, true);
    }
    $payload = [
        'mini' => (int) ($state['mini'] ?? SLOT_JP_SEEDS['mini']),
        'minor' => (int) ($state['minor'] ?? SLOT_JP_SEEDS['minor']),
        'major' => (int) ($state['major'] ?? SLOT_JP_SEEDS['major']),
        'grand' => (int) ($state['grand'] ?? SLOT_JP_SEEDS['grand']),
        'updatedAt' => time(),
    ];
    $json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
    if ($json === false) {
        return;
    }
    $fp = @fopen($path, 'c+b');
    if ($fp === false) {
        @file_put_contents($path, $json, LOCK_EX);

        return;
    }
    try {
        if (!flock($fp, LOCK_EX)) {
            fclose($fp);

            return;
        }
        ftruncate($fp, 0);
        rewind($fp);
        fwrite($fp, $json);
        fflush($fp);
        flock($fp, LOCK_UN);
    } finally {
        fclose($fp);
    }
}

function slot_jackpots_public(array $state): array
{
    $out = [];
    foreach (SLOT_JP_TIERS as $tier) {
        $out[$tier] = (int) ($state[$tier] ?? SLOT_JP_SEEDS[$tier]);
    }

    return $out;
}

function slot_jackpots_contribute(int $bet): array
{
    if ($bet <= 0) {
        return slot_jackpots_read();
    }
    $state = slot_jackpots_read();
    $pool = (int) floor($bet * SLOT_JP_CONTRIB_RATE);
    if ($pool < 1) {
        $pool = 1;
    }
    foreach (SLOT_JP_TIERS as $tier) {
        $share = (int) floor($pool * (SLOT_JP_CONTRIB_SPLIT[$tier] ?? 0.25));
        if ($share < 1) {
            $share = 1;
        }
        $state[$tier] = (int) $state[$tier] + $share;
    }
    slot_jackpots_write($state);

    return $state;
}

/**
 * @return array{tier: string, amount: int}|null
 */
function slot_jackpots_roll_win(int $bet): ?array
{
    $betFactor = min(4.0, max(1.0, $bet / 50.0));
    $roll = random_int(1, 1_000_000);
    $tier = null;
    foreach (['grand', 'major', 'minor', 'mini'] as $t) {
        $odds = (int) floor((SLOT_JP_ODDS[$t] ?? 0) * $betFactor);
        if ($odds > 0 && $roll <= $odds) {
            $tier = $t;
            break;
        }
    }
    if ($tier === null) {
        return null;
    }
    $state = slot_jackpots_read();
    $amount = (int) ($state[$tier] ?? SLOT_JP_SEEDS[$tier]);
    $state[$tier] = (int) SLOT_JP_SEEDS[$tier];
    slot_jackpots_write($state);

    return ['tier' => $tier, 'amount' => $amount];
}

/**
 * Triple jackpot symbol — weighted tier pick.
 *
 * @return array{tier: string, amount: int}|null
 */
function slot_jackpots_award_symbol_win(): ?array
{
    $u = random_int(1, 1000);
    $tier = 'mini';
    if ($u <= 2) {
        $tier = 'grand';
    } elseif ($u <= 12) {
        $tier = 'major';
    } elseif ($u <= 80) {
        $tier = 'minor';
    }
    $state = slot_jackpots_read();
    $amount = (int) ($state[$tier] ?? SLOT_JP_SEEDS[$tier]);
    $state[$tier] = (int) SLOT_JP_SEEDS[$tier];
    slot_jackpots_write($state);

    return ['tier' => $tier, 'amount' => $amount];
}
