<?php
/**
 * Rewarded-ads "watch N ads to unlock M hours ad-free" endpoints.
 *
 * Endpoints (mounted by the front-controller router):
 *
 *   POST /api/user/grant-ad-free
 *       body: { "hours": float (default 2.0, max 24) }
 *       auth: required (Bearer JWT)
 *       returns: { "ad_free_until": ISO, "granted_hours": N, "seconds_remaining": int }
 *
 *   GET  /api/user/ad-free-status
 *       auth: required (Bearer JWT)
 *       returns: { "ad_free_until": ISO|null, "seconds_remaining": int, "active": bool }
 *
 * Storage: `users.ad_free_until` (VARCHAR ISO datetime, nullable).
 * Added idempotently by `ensure_schema()` in api/lib/db.php — see the
 * additive migration block. No data loss for existing rows.
 */
declare(strict_types=1);

function _ad_free_now_utc(): string {
    return gmdate('c'); // ISO 8601, UTC, e.g. 2026-05-21T14:09:49+00:00
}

function _ad_free_parse(?string $iso): ?DateTimeImmutable {
    if (!$iso) return null;
    try {
        return new DateTimeImmutable($iso);
    } catch (Throwable $e) {
        return null;
    }
}

function _ad_free_seconds_remaining(?string $until_iso): int {
    $until = _ad_free_parse($until_iso);
    if (!$until) return 0;
    $now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
    $diff = $until->getTimestamp() - $now->getTimestamp();
    return $diff > 0 ? $diff : 0;
}

function route_user_grant_ad_free(): void {
    $user = require_auth(); // throws 401 if no valid JWT
    $body = read_json_body();
    $hours = (float)($body['hours'] ?? 2.0);
    if ($hours <= 0)   $hours = 2.0;
    if ($hours > 24.0) $hours = 24.0;

    // Admins get a no-op — they never see ads anyway.
    if (($user['role'] ?? '') === 'admin') {
        $row = db()->prepare('SELECT ad_free_until FROM users WHERE id = ?');
        $row->execute([$user['id']]);
        $r = $row->fetch();
        send_json([
            'ad_free_until'      => $r['ad_free_until'] ?? null,
            'granted_hours'      => 0.0,
            'seconds_remaining'  => _ad_free_seconds_remaining($r['ad_free_until'] ?? null),
        ]);
        return;
    }

    // Extend (don't overwrite). If existing window is in the past, start
    // from now so back-to-back rewards stack predictably.
    $sel = db()->prepare('SELECT ad_free_until FROM users WHERE id = ?');
    $sel->execute([$user['id']]);
    $current = $sel->fetch()['ad_free_until'] ?? null;
    $base = _ad_free_parse($current);
    $now  = new DateTimeImmutable('now', new DateTimeZone('UTC'));
    if (!$base || $base < $now) $base = $now;

    $secondsToAdd = (int)round($hours * 3600);
    $new_until    = $base->modify('+' . $secondsToAdd . ' seconds');
    $iso = $new_until->format(DateTimeInterface::ATOM);

    $upd = db()->prepare('UPDATE users SET ad_free_until = ? WHERE id = ?');
    $upd->execute([$iso, $user['id']]);

    send_json([
        'ad_free_until'      => $iso,
        'granted_hours'      => $hours,
        'seconds_remaining'  => _ad_free_seconds_remaining($iso),
    ]);
}

function route_user_ad_free_status(): void {
    $user = require_auth();
    $sel = db()->prepare('SELECT ad_free_until FROM users WHERE id = ?');
    $sel->execute([$user['id']]);
    $iso = $sel->fetch()['ad_free_until'] ?? null;
    send_json([
        'ad_free_until'     => $iso,
        'seconds_remaining' => _ad_free_seconds_remaining($iso),
        'active'            => _ad_free_seconds_remaining($iso) > 0,
    ]);
}
