<?php
// Rewards endpoint for ping-pong 1v1.
// Called by the Node match server after every match ends.
// Saves the result to match_results, updates user_stats and transactions inline.

require_once __DIR__ . '/internal/respond.php';
require_once __DIR__ . '/internal/env.php';
require_once __DIR__ . '/internal/hmac.php';
require_once __DIR__ . '/../../../administration/includes/config.php';

if (!isset($pdo) || !($pdo instanceof PDO)) {
    og_respond(['success' => false, 'error' => 'Database connection not initialized'], 500);
}

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    exit(0);
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    og_respond(['success' => false, 'error' => 'Method not allowed'], 405);
}

$secret = og_env('PINGPONG_1V1_SHARED_SECRET');
if (!$secret) {
    og_respond(['success' => false, 'error' => 'Server not configured (missing PINGPONG_1V1_SHARED_SECRET)'], 500);
}

$raw = file_get_contents('php://input');
$check = og_require_node_signature($secret, $raw, 60000);
if (empty($check['ok'])) {
    og_respond(['success' => false, 'error' => 'Invalid signature', 'code' => $check['error']], 401);
}

$payload = json_decode($raw, true);
if (!$payload || !is_array($payload)) {
    og_respond(['success' => false, 'error' => 'Invalid JSON'], 400);
}

// matchKey is always set by Node (internal ID like "m_abc123") — primary unique key.
// matchId may be 0 if MySQL was unavailable when the match was created — that is OK.
$matchKey       = isset($payload['matchKey'])        ? trim((string) $payload['matchKey'])        : '';
$matchId        = isset($payload['matchId'])         ? (int)         $payload['matchId']          : 0;
$winnerUserId   = isset($payload['winnerUserId'])    ? (int)         $payload['winnerUserId']     : 0;
$loserUserId    = isset($payload['loserUserId'])     ? (int)         $payload['loserUserId']      : 0;
$winnerUsername = isset($payload['winnerUsername'])  ? (string)      $payload['winnerUsername']   : '';
$loserUsername  = isset($payload['loserUsername'])   ? (string)      $payload['loserUsername']    : '';
$isDraw         = !empty($payload['isDraw']);
$leftUserId     = isset($payload['players']['left']['userId'])  ? (int)    $payload['players']['left']['userId']  : 0;
$rightUserId    = isset($payload['players']['right']['userId']) ? (int)    $payload['players']['right']['userId'] : 0;
$leftUsername   = isset($payload['players']['left']['username'])  ? (string) $payload['players']['left']['username']  : '';
$rightUsername  = isset($payload['players']['right']['username']) ? (string) $payload['players']['right']['username'] : '';
$score          = isset($payload['score'])           ? (string)      $payload['score']            : '';
$reason         = isset($payload['reason'])          ? (string)      $payload['reason']           : '';
$endedAt        = isset($payload['endedAt'])         ? (string)      $payload['endedAt']          : gmdate('Y-m-d H:i:s');
$setsLeft       = (int) ($payload['sets']['left']    ?? 0);
$setsRight      = (int) ($payload['sets']['right']   ?? 0);

if ($matchKey === '') {
    og_respond(['success' => false, 'error' => 'Missing required field: matchKey'], 400);
}

if ($isDraw) {
    if ($leftUserId <= 0 || $rightUserId <= 0) {
        og_respond(['success' => false, 'error' => 'Missing required draw fields (players.left.userId, players.right.userId)'], 400);
    }
    // Keep legacy columns populated in match_results by mapping draw sides to winner/loser fields.
    if ($winnerUserId <= 0) $winnerUserId = $leftUserId;
    if ($loserUserId <= 0) $loserUserId = $rightUserId;
    if ($winnerUsername === '') $winnerUsername = $leftUsername;
    if ($loserUsername === '') $loserUsername = $rightUsername;
} else if ($winnerUserId <= 0 || $loserUserId <= 0) {
    og_respond(['success' => false, 'error' => 'Missing required fields (matchKey, winnerUserId, loserUserId)'], 400);
}

// ─── Ensure tables exist ──────────────────────────────────────────────────────

$pdo->exec("CREATE TABLE IF NOT EXISTS match_results (
    id              BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    match_key       VARCHAR(100)    NOT NULL,
    match_id        BIGINT UNSIGNED NULL,
    discipline      VARCHAR(50)     NOT NULL DEFAULT 'ping-pong',
    mode            VARCHAR(50)     NOT NULL DEFAULT '1v1',
    winner_user_id  BIGINT UNSIGNED NOT NULL,
    loser_user_id   BIGINT UNSIGNED NOT NULL,
    winner_username VARCHAR(100)    NOT NULL DEFAULT '',
    loser_username  VARCHAR(100)    NOT NULL DEFAULT '',
    score           VARCHAR(200)    NOT NULL DEFAULT '',
    sets_winner     TINYINT         NOT NULL DEFAULT 0,
    sets_loser      TINYINT         NOT NULL DEFAULT 0,
    reason          VARCHAR(50)     NOT NULL DEFAULT '',
    ended_at        DATETIME        NULL,
    payload_json    LONGTEXT        NULL,
    created_at      TIMESTAMP       NOT NULL DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uniq_match_key (discipline, mode, match_key),
    INDEX idx_winner (winner_user_id),
    INDEX idx_loser  (loser_user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

$pdo->exec("CREATE TABLE IF NOT EXISTS rewards_jobs (
    id           BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    discipline   VARCHAR(50)  NOT NULL,
    mode         VARCHAR(50)  NOT NULL,
    match_key    VARCHAR(100) NOT NULL DEFAULT '',
    match_id     BIGINT UNSIGNED NOT NULL DEFAULT 0,
    payload_json LONGTEXT     NOT NULL,
    status       VARCHAR(20)  NOT NULL DEFAULT 'queued',
    attempts     INT          NOT NULL DEFAULT 0,
    result_json  LONGTEXT     NULL,
    last_error   TEXT         NULL,
    created_at   TIMESTAMP    NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at   TIMESTAMP    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uniq_match_key (discipline, mode, match_key),
    INDEX idx_status_created  (status, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

// If rewards_jobs was created before this version, add match_key column if missing
$mkExists = (int) $pdo->query(
    "SELECT COUNT(*) FROM information_schema.columns
     WHERE table_schema = DATABASE() AND table_name = 'rewards_jobs' AND column_name = 'match_key'"
)->fetchColumn();
if (!$mkExists) {
    $pdo->exec("ALTER TABLE rewards_jobs ADD COLUMN match_key VARCHAR(100) NOT NULL DEFAULT '' AFTER mode");
    // Try to add unique index; ignore error if it already exists under another name
    try {
        $pdo->exec("ALTER TABLE rewards_jobs ADD UNIQUE KEY uniq_match_key (discipline, mode, match_key)");
    } catch (Throwable $ignored) {}
}

$pdo->exec("CREATE TABLE IF NOT EXISTS transactions (
    id          BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id     BIGINT UNSIGNED NOT NULL,
    type        VARCHAR(20)     NOT NULL,
    amount      DECIMAL(12,2)   NOT NULL,
    title       VARCHAR(255)    NOT NULL,
    description TEXT            NULL,
    category    VARCHAR(50)     NULL,
    created_at  TIMESTAMP       NOT NULL DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_created (user_id, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

// ─── Enqueue rewards job (idempotent by match_key) ────────────────────────────

$pdo->prepare(
    "INSERT IGNORE INTO rewards_jobs
        (discipline, mode, match_key, match_id, payload_json, status)
     VALUES ('ping-pong', '1v1', :mk, :mid, :pj, 'queued')"
)->execute([
    ':mk'  => $matchKey,
    ':mid' => $matchId,
    ':pj'  => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);

$jobRow = $pdo->prepare(
    "SELECT id, status FROM rewards_jobs
     WHERE discipline = 'ping-pong' AND mode = '1v1' AND match_key = :mk"
);
$jobRow->execute([':mk' => $matchKey]);
$job = $jobRow->fetch(PDO::FETCH_ASSOC);
if (!$job) {
    og_respond(['success' => false, 'error' => 'Failed to enqueue rewards job'], 500);
}
$jobId = (int) $job['id'];

// ─── Process inline (no cron required) ───────────────────────────────────────

if ($job['status'] === 'queued') {
    $claim = $pdo->prepare(
        "UPDATE rewards_jobs
         SET status = 'processing', attempts = attempts + 1
         WHERE id = :id AND status = 'queued'"
    );
    $claim->execute([':id' => $jobId]);

    if ($claim->rowCount() > 0) {
        $winnerReward = 1.00;
        $loserReward  = 0.20;
        $drawRefund   = 1.00;
        // Determine sets per side: winner always has more sets
        $winnerSets = max($setsLeft, $setsRight);
        $loserSets  = min($setsLeft, $setsRight);
        $matchLabel = $matchId > 0 ? 'Mecz #' . $matchId : 'Mecz ' . $matchKey;

        try {
            // Ensure both players have a user_stats row
            $insStats = $pdo->prepare(
                "INSERT IGNORE INTO user_stats
                    (user_id, balance, matches_played, matches_won, matches_lost, matches_draw,
                     tournaments_played, tournaments_won, leagues_participated,
                     total_income, total_expenses, total_transactions, account_status)
                 VALUES (?, 0.00, 0, 0, 0, 0, 0, 0, 0, 0.00, 0.00, 0, 'active')"
            );
            $insStats->execute([$winnerUserId]);
            $insStats->execute([$loserUserId]);
            if ($isDraw) {
                $insStats->execute([$leftUserId]);
                $insStats->execute([$rightUserId]);
            }

            $pdo->beginTransaction();

            // 1. Save match result record
            $pdo->prepare(
                "INSERT IGNORE INTO match_results
                    (match_key, match_id, discipline, mode,
                     winner_user_id, loser_user_id, winner_username, loser_username,
                     score, sets_winner, sets_loser, reason, ended_at, payload_json)
                 VALUES (?, ?, 'ping-pong', '1v1', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
            )->execute([
                $matchKey,
                $matchId > 0 ? $matchId : null,
                $winnerUserId, $loserUserId,
                $winnerUsername, $loserUsername,
                $score, $winnerSets, $loserSets,
                $reason, $endedAt,
                json_encode($payload, JSON_UNESCAPED_UNICODE),
            ]);

            // 2/3. Update stats
            if ($isDraw) {
                $updDraw = $pdo->prepare(
                    "UPDATE user_stats
                     SET matches_played     = matches_played     + 1,
                         matches_draw       = matches_draw       + 1,
                         balance            = balance            + ?,
                         total_income       = total_income       + ?,
                         total_transactions = total_transactions + 1
                     WHERE user_id = ?"
                );
                $updDraw->execute([$drawRefund, $drawRefund, $leftUserId]);
                $updDraw->execute([$drawRefund, $drawRefund, $rightUserId]);
            } else {
                $pdo->prepare(
                    "UPDATE user_stats
                     SET matches_played     = matches_played     + 1,
                         matches_won        = matches_won        + 1,
                         balance            = balance            + ?,
                         total_income       = total_income       + ?,
                         total_transactions = total_transactions + 1
                     WHERE user_id = ?"
                )->execute([$winnerReward, $winnerReward, $winnerUserId]);

                $pdo->prepare(
                    "UPDATE user_stats
                     SET matches_played     = matches_played     + 1,
                         matches_lost       = matches_lost       + 1,
                         balance            = balance            + ?,
                         total_income       = total_income       + ?,
                         total_transactions = total_transactions + 1
                     WHERE user_id = ?"
                )->execute([$loserReward, $loserReward, $loserUserId]);
            }

            // 4. Insert transaction records
            $txStmt = $pdo->prepare(
                "INSERT INTO transactions (user_id, type, amount, title, description, category)
                 VALUES (?, 'income', ?, ?, ?, 'match')"
            );
            if ($isDraw) {
                $txStmt->execute([
                    $leftUserId,
                    $drawRefund,
                    'Ping-Pong 1v1 - remis (zwrot stawki)',
                    $matchLabel . ' | ' . $score,
                ]);
                $txStmt->execute([
                    $rightUserId,
                    $drawRefund,
                    'Ping-Pong 1v1 - remis (zwrot stawki)',
                    $matchLabel . ' | ' . $score,
                ]);
            } else {
                $txStmt->execute([
                    $winnerUserId,
                    $winnerReward,
                    'Ping-Pong 1v1 - wygrana',
                    $matchLabel . ' | ' . $score,
                ]);
                $txStmt->execute([
                    $loserUserId,
                    $loserReward,
                    'Ping-Pong 1v1 - udział',
                    $matchLabel . ' | ' . $score,
                ]);
            }

            // 5. Mark job done
            $result = $isDraw
                ? [
                    'draw'      => [
                        'left'  => ['userId' => $leftUserId,  'username' => $leftUsername,  'reward' => (float) $drawRefund],
                        'right' => ['userId' => $rightUserId, 'username' => $rightUsername, 'reward' => (float) $drawRefund],
                    ],
                    'animation' => ['type' => 'coins', 'durationMs' => 2500],
                    'match'     => ['matchKey' => $matchKey, 'matchId' => $matchId, 'score' => $score],
                  ]
                : [
                    'winner'    => ['userId' => $winnerUserId, 'username' => $winnerUsername, 'reward' => (float) $winnerReward],
                    'loser'     => ['userId' => $loserUserId,  'username' => $loserUsername,  'reward' => (float) $loserReward],
                    'animation' => ['type' => 'coins', 'durationMs' => 2500],
                    'match'     => ['matchKey' => $matchKey, 'matchId' => $matchId, 'score' => $score],
                  ];
            $pdo->prepare(
                "UPDATE rewards_jobs SET status = 'done', result_json = :res, last_error = NULL WHERE id = :id"
            )->execute([':id' => $jobId, ':res' => json_encode($result, JSON_UNESCAPED_UNICODE)]);

            $pdo->commit();
        } catch (Throwable $e) {
            if ($pdo->inTransaction()) $pdo->rollBack();
            $pdo->prepare(
                "UPDATE rewards_jobs SET status = 'queued', last_error = :err WHERE id = :id"
            )->execute([':id' => $jobId, ':err' => $e->getMessage()]);
        }
    }
}

// Return final status
$finalStatus = $pdo->prepare("SELECT status FROM rewards_jobs WHERE id = :id");
$finalStatus->execute([':id' => $jobId]);
$statusVal = $finalStatus->fetchColumn() ?: 'queued';

og_respond([
    'success' => true,
    'jobId'   => $jobId,
    'status'  => $statusVal,
]);
