<?php
// =============================================================================
// SportsProvider interface — every feed source (TheSportsDB free, paid SportsDB,
// API-Football, manual entry) implements this contract.
//
// The sync script calls fetch_leagues() then fetch_events() and upserts the
// returned arrays into sports_leagues / sports_events.
// =============================================================================

interface SportsProvider
{
    /** Return the wire name stored in sports_leagues.source / sports_events.source. */
    public function name(): string;

    /**
     * Return an array of leagues:
     *   [ ['source_league_id' => '4328', 'name' => 'English Premier League',
     *      'country' => 'England', 'logo_url' => 'https://…'], ... ]
     */
    public function fetch_leagues(): array;

    /**
     * Return an array of events for the given league IDs in the given date
     * window:
     *   [ ['source_event_id' => '12345', 'source_league_id' => '4328',
     *      'home_team' => 'Arsenal', 'away_team' => 'Chelsea',
     *      'home_badge_url' => '…', 'away_badge_url' => '…',
     *      'kickoff_ts' => 1781476147, 'status' => 'UPCOMING',
     *      'home_score' => null, 'away_score' => null,
     *      'channels_csv' => 'Sky Sports,BT Sport'], ... ]
     *
     * `$league_ids` is the list of `source_league_id` values to filter by, or
     * an empty array to fetch all enabled leagues.
     * `$from_ts` / `$to_ts` are unix timestamps bracketing the window.
     */
    public function fetch_events(array $league_ids, int $from_ts, int $to_ts): array;
}

// ---------------------------------------------------------------------------
// Cache helpers — every provider should round-trip through these so a cron
// that runs every 5 min doesn't hammer the upstream API.
// ---------------------------------------------------------------------------

function sports_cache_get(string $provider, string $endpoint, int $max_age_seconds): ?array
{
    $row = db_one('SELECT payload_json, fetched_at FROM sports_feed_cache WHERE provider=? AND endpoint=?',
                  [$provider, $endpoint]);
    if (!$row) return null;
    if ((time() - (int)$row['fetched_at']) > $max_age_seconds) return null;
    $payload = json_decode($row['payload_json'], true);
    return is_array($payload) ? $payload : null;
}

function sports_cache_set(string $provider, string $endpoint, array $payload): void
{
    db_exec('INSERT OR REPLACE INTO sports_feed_cache (provider, endpoint, fetched_at, payload_json)
             VALUES (?, ?, ?, ?)',
            [$provider, $endpoint, time(), json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)]);
}

// HTTPS fetch helper used by providers — short timeout, follows redirects,
// returns null on any failure. Cron path; not exposed to clients.
function sports_http_get(string $url, array $headers = [], int $timeout_seconds = 8): ?string
{
    // Only fetch over HTTP(S). Lock redirects to the same protocol set so a
    // hostile upstream can't bounce us to file://, gopher://, dict://, ldap://
    // or similar SSRF amplifiers.
    $proto_mask = (defined('CURLPROTO_HTTPS') ? CURLPROTO_HTTPS : 0)
                | (defined('CURLPROTO_HTTP')  ? CURLPROTO_HTTP  : 0);
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS      => 3,
        CURLOPT_TIMEOUT        => $timeout_seconds,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_PROTOCOLS       => $proto_mask,
        CURLOPT_REDIR_PROTOCOLS => $proto_mask,
        CURLOPT_HTTPHEADER     => array_merge(
            ['User-Agent: b3studios-panel/1.0', 'Accept: application/json'],
            $headers
        ),
    ]);
    $body = curl_exec($ch);
    $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if ($body === false || $code < 200 || $code >= 300) return null;
    return (string)$body;
}
