<?php
declare(strict_types=1);

require_once __DIR__ . '/sport_api_lib.php';

const SPECIAL_ODDS_MIN_STAKE = 10;
const SPECIAL_ODDS_MAX_STAKE = 100000;
const SPECIAL_ODDS_MIN_ODDS = 1.01;
const SPECIAL_ODDS_MAX_ODDS = 500.0;

function special_odds_result_from_score(int $home, int $away): string
{
    if ($home > $away) {
        return 'home';
    }
    if ($home < $away) {
        return 'away';
    }

    return 'draw';
}

function special_odds_decimal_for_pick(array $row, string $pick): float
{
    $p = strtolower(trim($pick));
    if (isset($row['odds_offered']) && (float) $row['odds_offered'] >= SPECIAL_ODDS_MIN_ODDS - 0.0001) {
        $ap = strtolower(trim((string) ($row['admin_pick'] ?? 'home')));
        if ($p === $ap) {
            return (float) $row['odds_offered'];
        }

        return 0.0;
    }
    if ($p === 'home') {
        return (float) $row['odds_home'];
    }
    if ($p === 'draw') {
        return (float) $row['odds_draw'];
    }
    if ($p === 'away') {
        return (float) $row['odds_away'];
    }

    return 0.0;
}

function special_odds_payout_amount(int $stake, float $decimalOdds): int
{
    return (int) floor($stake * $decimalOdds);
}

function special_odds_sync_match_from_api(PDO $pdo, int $matchId): array
{
    $st = $pdo->prepare('SELECT * FROM special_odds_matches WHERE id = :id LIMIT 1');
    $st->execute([':id' => $matchId]);
    $row = $st->fetch(PDO::FETCH_ASSOC);
    if (!$row) {
        return ['ok' => false, 'error' => 'not_found'];
    }
    if ((string) ($row['status'] ?? '') !== 'open') {
        return ['ok' => true, 'settled' => false];
    }

    $ext = trim((string) ($row['external_event_id'] ?? ''));
    if ($ext === '') {
        return ['ok' => false, 'error' => 'no_external_id'];
    }

    $raw = mocker_sport_event_fetch_json($ext);
    $now = time();
    if ($raw === null) {
        $u = $pdo->prepare('UPDATE special_odds_matches SET last_api_sync_at = :t, updated_at = :t2 WHERE id = :id');
        $u->execute([':t' => $now, ':t2' => $now, ':id' => $matchId]);

        return ['ok' => false, 'error' => 'api_fetch_failed'];
    }

    $snippet = json_encode($raw, JSON_UNESCAPED_UNICODE);
    if (strlen($snippet) > 12000) {
        $snippet = substr($snippet, 0, 12000) . '…';
    }

    $parsed = mocker_sport_parse_event_result($raw);
    $upd = $pdo->prepare(
        'UPDATE special_odds_matches SET last_api_sync_at = :sync, api_raw_json = :raw, updated_at = :u WHERE id = :id'
    );
    $upd->execute([':sync' => $now, ':raw' => $snippet, ':u' => $now, ':id' => $matchId]);

    if ($parsed === null) {
        return ['ok' => false, 'error' => 'parse_failed'];
    }
    if (!$parsed['finished']) {
        return ['ok' => true, 'settled' => false];
    }

    $hg = $parsed['home'];
    $ag = $parsed['away'];
    $result = special_odds_result_from_score($hg, $ag);
    special_odds_apply_settlement($pdo, $matchId, $result, $hg, $ag);

    return ['ok' => true, 'settled' => true];
}

function special_odds_apply_settlement(PDO $pdo, int $matchId, string $result, int $homeGoals, int $awayGoals): void
{
    $now = time();
    $pdo->beginTransaction();
    try {
        $u = $pdo->prepare(
            'UPDATE special_odds_matches SET status = \'settled\', result = :r, home_goals = :hg, away_goals = :ag, updated_at = :t WHERE id = :id AND status = \'open\''
        );
        $u->execute([':r' => $result, ':hg' => $homeGoals, ':ag' => $awayGoals, ':t' => $now, ':id' => $matchId]);
        if ($u->rowCount() === 0) {
            $pdo->rollBack();

            return;
        }

        $bets = $pdo->prepare('SELECT * FROM special_odds_bets WHERE match_id = :m AND status = \'pending\'');
        $bets->execute([':m' => $matchId]);
        foreach ($bets->fetchAll(PDO::FETCH_ASSOC) as $b) {
            $pick = strtolower((string) ($b['pick'] ?? ''));
            $won = $pick === strtolower($result);
            $bid = (int) $b['id'];
            $uid = (int) $b['user_id'];
            if ($won) {
                $pay = (int) $b['payout_on_win'];
                $pdo->prepare('UPDATE users SET coins = coins + :p WHERE id = :u')->execute([':p' => $pay, ':u' => $uid]);
                $pdo->prepare(
                    'UPDATE special_odds_bets SET status = \'won\', settled_at = :t WHERE id = :id'
                )->execute([':t' => $now, ':id' => $bid]);
            } else {
                $pdo->prepare(
                    'UPDATE special_odds_bets SET status = \'lost\', settled_at = :t WHERE id = :id'
                )->execute([':t' => $now, ':id' => $bid]);
            }
        }
        $pdo->commit();
    } catch (Throwable $e) {
        $pdo->rollBack();
        throw $e;
    }
}

function special_odds_sync_all_open(PDO $pdo): array
{
    $errors = [];
    $settled = 0;
    $st = $pdo->query(
        "SELECT id FROM special_odds_matches WHERE status = 'open' ORDER BY kickoff_at ASC"
    );
    $ids = $st ? $st->fetchAll(PDO::FETCH_COLUMN) : [];
    $checked = 0;
    foreach ($ids as $id) {
        $mid = (int) $id;
        if ($mid <= 0) {
            continue;
        }
        ++$checked;
        try {
            $r = special_odds_sync_match_from_api($pdo, $mid);
            if (!empty($r['settled'])) {
                ++$settled;
            }
            if ($r['ok'] === false && isset($r['error'])) {
                $errors[] = "match {$mid}: " . (string) $r['error'];
            }
        } catch (Throwable $e) {
            $errors[] = "match {$mid}: " . $e->getMessage();
        }
    }

    return ['checked' => $checked, 'settled' => $settled, 'errors' => $errors];
}

function special_odds_manual_settle(PDO $pdo, int $matchId, string $result): void
{
    $r = strtolower(trim($result));
    if ($r === 'home') {
        special_odds_apply_settlement($pdo, $matchId, 'home', 1, 0);
    } elseif ($r === 'away') {
        special_odds_apply_settlement($pdo, $matchId, 'away', 0, 1);
    } else {
        special_odds_apply_settlement($pdo, $matchId, 'draw', 0, 0);
    }
}

function special_odds_cancel_match(PDO $pdo, int $matchId): bool
{
    $now = time();
    $pdo->beginTransaction();
    try {
        $st = $pdo->prepare("SELECT id FROM special_odds_matches WHERE id = :id AND status = 'open' LIMIT 1");
        $st->execute([':id' => $matchId]);
        if (!$st->fetch()) {
            $pdo->rollBack();

            return false;
        }
        $bets = $pdo->prepare("SELECT id, user_id, stake FROM special_odds_bets WHERE match_id = :m AND status = 'pending'");
        $bets->execute([':m' => $matchId]);
        foreach ($bets->fetchAll(PDO::FETCH_ASSOC) as $b) {
            $uid = (int) $b['user_id'];
            $stake = (int) $b['stake'];
            $pdo->prepare('UPDATE users SET coins = coins + :s WHERE id = :u')->execute([':s' => $stake, ':u' => $uid]);
            $pdo->prepare(
                "UPDATE special_odds_bets SET status = 'void', settled_at = :t WHERE id = :id"
            )->execute([':t' => $now, ':id' => (int) $b['id']]);
        }
        $pdo->prepare(
            "UPDATE special_odds_matches SET status = 'cancelled', updated_at = :t WHERE id = :id"
        )->execute([':t' => $now, ':id' => $matchId]);
        $pdo->commit();

        return true;
    } catch (Throwable $e) {
        $pdo->rollBack();
        throw $e;
    }
}
