<?php
/**
 * GESTOR CYBER - _core.php
 * Funções compartilhadas entre player_api.php e get.php
 * Não acessar diretamente.
 */

if (!defined('GESTOR_CYBER')) { http_response_code(403); exit; }

define('DB_FILE', __DIR__ . '/database.json');
define('CACHE_DIR', sys_get_temp_dir());
define('CACHE_TTL', 600); // 10 minutos

// ─── BD ───────────────────────────────────────────────────────────────────────
function gc_db(): array {
    if (!file_exists(DB_FILE)) return [];
    return json_decode(file_get_contents(DB_FILE), true) ?? [];
}

// ─── Expiração ────────────────────────────────────────────────────────────────
function gc_expired(array $c): bool {
    return empty($c['expires_at']) || strtotime($c['expires_at']) < time();
}

// ─── Autenticação ─────────────────────────────────────────────────────────────
function gc_auth(string $u, string $p): ?array {
    if (!$u || !$p) return null;
    $db   = gc_db();
    $hash = hash('sha256', $p);
    foreach ($db['clients'] ?? [] as $c) {
        if ($c['username'] !== $u || $c['password'] !== $hash) continue;
        if (($c['status'] ?? '') !== 'active') return null;
        if (gc_expired($c)) {
            $trust = (int)($db['config']['trust_renewal_days'] ?? 2);
            if (time() > strtotime($c['expires_at']) + $trust * 86400) return null;
        }
        return ['client' => $c, 'db' => $db];
    }
    return null;
}

// ─── Fonte ativa ──────────────────────────────────────────────────────────────
function gc_source(array $db): ?array {
    foreach ($db['sources'] ?? [] as $s) {
        if (($s['status'] ?? 'active') === 'active') return $s;
    }
    return null;
}

// ─── Base URL da fonte ────────────────────────────────────────────────────────
function gc_base(array $src): string {
    $p = parse_url($src['url']);
    return ($p['scheme'] ?? 'http') . '://' . ($p['host'] ?? '') .
           (isset($p['port']) ? ':' . $p['port'] : '');
}

// ─── Base URL do nosso servidor ───────────────────────────────────────────────
function gc_our(): string {
    $s = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    return $s . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost');
}

// ─── HTTP fetch (cURL primeiro, fallback file_get_contents) ──────────────────
function gc_fetch(string $url, int $timeout = 45): string|false {
    // Tenta cURL primeiro (funciona mesmo com allow_url_fopen=off)
    if (function_exists('curl_init')) {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL            => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS      => 5,
            CURLOPT_TIMEOUT        => $timeout,
            CURLOPT_CONNECTTIMEOUT => 15,
            CURLOPT_USERAGENT      => 'Mozilla/5.0 (compatible; IPTV)',
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_ENCODING       => '',
            CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_1_1,
        ]);
        $result = curl_exec($ch);
        $code   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err    = curl_error($ch);
        curl_close($ch);

        if ($result !== false && strlen($result) > 5) return $result;
    }

    // Fallback: file_get_contents
    if (ini_get('allow_url_fopen')) {
        $ctx = stream_context_create([
            'http' => [
                'timeout'         => $timeout,
                'follow_location' => true,
                'ignore_errors'   => true,
                'user_agent'      => 'Mozilla/5.0 (compatible; IPTV)',
            ],
            'ssl'  => [
                'verify_peer'      => false,
                'verify_peer_name' => false,
            ]
        ]);
        return @file_get_contents($url, false, $ctx);
    }

    return false;
}

// ─── Buscar M3U com cache ─────────────────────────────────────────────────────
function gc_m3u(array $src): string {
    $cache = CACHE_DIR . '/gc_m3u_' . md5($src['id'] ?? $src['url']) . '.cache';

    // Cache válido?
    if (file_exists($cache) && (time() - filemtime($cache)) < CACHE_TTL) {
        $data = file_get_contents($cache);
        if ($data && strlen($data) > 100) return $data;
    }

    $base = gc_base($src);
    $u    = urlencode($src['username'] ?? '');
    $p    = urlencode($src['password'] ?? '');

    // Tentar diferentes endpoints da fonte
    $urls = [
        "$base/get.php?username=$u&password=$p&type=m3u_plus&output=ts",
        "$base/get.php?username=$u&password=$p&type=m3u&output=ts",
        $src['url'], // URL direta se for M3U
    ];

    foreach ($urls as $url) {
        $content = gc_fetch($url, 60);
        if ($content && strlen($content) > 100 && str_contains($content, '#EXTM3U')) {
            @file_put_contents($cache, $content);
            return $content;
        }
    }

    return '';
}

// ─── Parsear M3U ──────────────────────────────────────────────────────────────
function gc_parse(string $m3u): array {
    $lines   = explode("\n", str_replace("\r", '', $m3u));
    $streams = [];
    $cur     = null;
    $cats    = [];   // name => id
    $cat_id  = 1;
    $counter = 0;

    foreach ($lines as $line) {
        $line = trim($line);
        if ($line === '' || $line === '#EXTM3U') continue;

        if (str_starts_with($line, '#EXTINF')) {
            $cur = ['name'=>'','logo'=>'','group'=>'','tvg_id'=>'','url'=>'','type'=>'live','sid'=>0,'cid'=>0];
            if (preg_match('/tvg-name="([^"]*)"/', $line, $m))    $cur['name']   = $m[1];
            if (preg_match('/tvg-logo="([^"]*)"/', $line, $m))    $cur['logo']   = $m[1];
            if (preg_match('/tvg-id="([^"]*)"/', $line, $m))      $cur['tvg_id'] = $m[1];
            if (preg_match('/group-title="([^"]*)"/', $line, $m)) $cur['group']  = trim($m[1]);
            // Nome fallback após última vírgula
            if (!$cur['name']) {
                $pos = strrpos($line, ',');
                if ($pos !== false) $cur['name'] = trim(substr($line, $pos + 1));
            }
            // Tipo
            $lg = strtolower($cur['group']);
            if (str_contains($lg,'vod')||str_contains($lg,'movie')||str_contains($lg,'filme')||str_contains($lg,'film')) $cur['type'] = 'movie';
            elseif (str_contains($lg,'serie')) $cur['type'] = 'series';
            // Categoria
            $g = $cur['group'] ?: 'Geral';
            if (!isset($cats[$g])) $cats[$g] = $cat_id++;
            $cur['cid'] = $cats[$g];

        } elseif ($cur !== null && !str_starts_with($line, '#') && trim($line)) {
            $cur['url'] = $line;
            // Stream ID
            if (preg_match('#/(\d{3,})(?:[_.]|\?|$)#', $line, $m)) $cur['sid'] = (int)$m[1];
            else { $counter++; $cur['sid'] = 900000 + $counter; }
            $streams[] = $cur;
            $cur = null;
        }
    }

    return ['streams' => $streams, 'cats' => $cats];
}

// ─── Filtrar adulto ───────────────────────────────────────────────────────────
function gc_filter_adult(array $streams): array {
    return array_values(array_filter($streams, function($s) {
        $n = strtolower($s['name'].' '.$s['group']);
        return !str_contains($n,'xxx') && !str_contains($n,'+18')
            && !str_contains($n,'adult') && !str_contains($n,'erotic')
            && !str_contains($n,'porno') && !str_contains($n,'sex');
    }));
}

// ─── Reescrever URL de stream para passar pelo nosso proxy ────────────────────
function gc_rewrite(string $orig_url, string $our, string $user, string $pass): string {
    // Formato Xtream: /live/u/p/ID.ext
    if (preg_match('#/(live|movie|series)/[^/]+/[^/]+/(\d+)(\.\w+)?#', $orig_url, $m)) {
        return "$our/{$m[1]}/$user/$pass/{$m[2]}" . ($m[3] ?? '.ts');
    }
    // ID numérico no final da URL
    if (preg_match('#[/=](\d{3,})(\.\w+)?(?:[?&]|$)#', $orig_url, $m)) {
        return "$our/live/$user/$pass/{$m[1]}" . ($m[2] ?? '.ts');
    }
    // URL não reconhecida — retornar original (melhor do que quebrar)
    return $orig_url;
}

// ─── Categorias para JSON Xtream ──────────────────────────────────────────────
function gc_cats_json(array $streams, array $cats): array {
    $seen = []; $out = [];
    foreach ($streams as $s) {
        $g = $s['group'] ?: 'Geral';
        if (isset($seen[$g])) continue;
        $seen[$g] = true;
        $out[] = ['category_id' => (string)($cats[$g] ?? 0), 'category_name' => $g, 'parent_id' => 0];
    }
    return $out;
}
