<?php
// Desativa exibição de erros para não corromper o arquivo M3U
ini_set('display_errors', 0);
error_reporting(0);

// MÁGICA: Tempo infinito e liberação de memória para listas gigantes (100k+ canais) sem erro 500
set_time_limit(0);
ini_set('memory_limit', '-1');

require_once 'config.php';

// Inicia o buffer de saída
ob_start();

$pdo = getConexaoAtiva();
$pdo_int = getConexaoInterna();

$pdo->exec("SET NAMES utf8mb4");
$pdo->exec("SET SESSION sql_mode = ''");

$username = $_GET['username'] ?? '';
$password = $_GET['password'] ?? '';
$output   = $_GET['output'] ?? 'ts';

if (empty($username) || empty($password)) {
    header("HTTP/1.0 400 Bad Request");
    die("Parametros ausentes.");
}

// ====================================================================
// INTELIGÊNCIA ARTIFICIAL: DETECTA SE É XUI ONE OU XTREAM UI
// ====================================================================
$modo_ativo = 'interno';
try {
    $modo_ativo = $pdo_int->query("SELECT modo_ativo FROM configuracoes LIMIT 1")->fetchColumn() ?: 'interno';
} catch (Exception $e) {}

$tabela_clientes = ($modo_ativo === 'xui') ? '`lines`' : '`users`';
$tabela_categorias = 'stream_categories';
$tabela_series = 'series';
$tabela_episodios = 'series_episodes';
$col_sort = 'sort';
$pk_series = 'id';

if ($modo_ativo === 'xui') {
    $col_sort = 'episode_num';
    $pk_series = 'series_id';
    try { $pdo->query("SELECT 1 FROM streams_categories LIMIT 1"); $tabela_categorias = 'streams_categories'; } 
    catch (Exception $e) { try { $pdo->query("SELECT 1 FROM categories LIMIT 1"); $tabela_categorias = 'categories'; } catch (Exception $e2) { } }
    try { $pdo->query("SELECT 1 FROM streams_series LIMIT 1"); $tabela_series = 'streams_series'; } catch (Exception $e) {}
    try { $pdo->query("SELECT 1 FROM streams_episodes LIMIT 1"); $tabela_episodios = 'streams_episodes'; } catch (Exception $e) {}
}

// ====================================================================
// TRAVA BLINDADA (Evita Crash se as colunas novas não existirem)
// ====================================================================
try {
    $stmt = $pdo->prepare("SELECT id, username, exp_date, enabled, bouquet, is_restreamer FROM $tabela_clientes WHERE username = ? AND password = ? LIMIT 1");
    $stmt->execute([$username, $password]);
    $cliente = $stmt->fetch(PDO::FETCH_ASSOC);
} catch (Exception $e) {
    // Fallback caso o painel ainda não tenha rodado a atualização das tabelas
    $stmt = $pdo->prepare("SELECT id, username, exp_date, enabled FROM $tabela_clientes WHERE username = ? AND password = ? LIMIT 1");
    $stmt->execute([$username, $password]);
    $cliente = $stmt->fetch(PDO::FETCH_ASSOC);
    $cliente['bouquet'] = '';
    $cliente['is_restreamer'] = 0;
}

if (!$cliente || $cliente['enabled'] == 0 || ($cliente['exp_date'] != null && $cliente['exp_date'] != 0 && $cliente['exp_date'] < time())) {
    header("HTTP/1.0 401 Unauthorized");
    die("Usuario invalido ou vencido.");
}

// ====================================================================
// INTELIGÊNCIA DE PACOTES (BOUQUETS) DO CLIENTE
// ====================================================================
$allowed_streams = [];
$allowed_series = [];

if (!empty($cliente['bouquet'])) {
    $bouquets_json = json_decode($cliente['bouquet'], true);
    if (!empty($bouquets_json) && is_array($bouquets_json)) {
        $bq_ids = implode(',', array_map('intval', $bouquets_json));
        try {
            // Busca apenas os IDs exatos de Streams (Live e VOD) e Séries permitidos para o cliente
            $stmtBq = $pdo->query("SELECT bouquet_channels, bouquet_series FROM bouquets WHERE id IN ($bq_ids)");
            while ($bq = $stmtBq->fetch(PDO::FETCH_ASSOC)) {
                
                $ch_arr = json_decode($bq['bouquet_channels'] ?? '[]', true);
                if (is_array($ch_arr)) { foreach ($ch_arr as $c) { $allowed_streams[$c] = true; } }
                
                $sr_arr = json_decode($bq['bouquet_series'] ?? '[]', true);
                if (is_array($sr_arr)) { foreach ($sr_arr as $s) { $allowed_series[$s] = true; } }
            }
        } catch(Exception $e){}
    }
}

// Tenta atualizar a atividade (Silencioso caso a coluna não exista)
try { $pdo->prepare("UPDATE $tabela_clientes SET last_activity = ? WHERE id = ?")->execute([time(), $cliente['id']]); } catch(Exception $e){}

// ====================================================================
// CONFIGURAÇÃO DO MODO OCULTO (TOKEN) NO BANCO INTERNO
// ====================================================================
$usar_token = false;
$token_xui = "";
try {
    $stmtCfg = $pdo_int->query("SELECT value FROM custom_settings WHERE name = 'link_mode'");
    $link_mode = $stmtCfg->fetchColumn() ?: "0";
    if ($link_mode === "1") {
        $usar_token = true;
        $token_base = base64_encode($username . ":" . $password);
        $token_clean = str_replace(['+', '/', '='], ['-', '_', ''], $token_base);
        $token_xui = "NBR_" . $token_clean;
    }
} catch (Exception $e) {}

// ====================================================================
// INTELIGÊNCIA DE DNS (PAINEL vs STREAMING - LOAD BALANCER)
// ====================================================================
$protocolo_painel = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? "https://" : "http://";
$url_painel = $protocolo_painel . $_SERVER['HTTP_HOST'];

// MÁGICA: Independente do Modo Interno/Externo, ele pesquisa se existe Load Balancer
$url_streaming = $url_painel; 
$dns_encontrado = false;

// 1. Tenta Load Balancer (Ignorando a trava do modo_ativo)
try {
    $stmtLb = $pdo->query("SELECT ip_servidor, porta FROM servidores_lb WHERE status = 1 ORDER BY id DESC LIMIT 1");
    $lbAtivo = $stmtLb->fetch(PDO::FETCH_ASSOC);
    if ($lbAtivo && !empty($lbAtivo['ip_servidor'])) {
        $porta_lb = (isset($lbAtivo['porta']) && $lbAtivo['porta'] != 80 && $lbAtivo['porta'] != '') ? ":" . $lbAtivo['porta'] : "";
        $dns_val = trim($lbAtivo['ip_servidor']) . $porta_lb;
        if (strpos($dns_val, 'http') !== 0) $dns_val = "http://" . $dns_val;
        $url_streaming = rtrim($dns_val, '/');
        $dns_encontrado = true;
    }
} catch(Exception $e){}

// 2. Se não achou LB e não for Interno, tenta o Domínio Principal
if (!$dns_encontrado && $modo_ativo !== 'interno') {
    try {
        $tabela_servidores = ($modo_ativo === 'xui') ? 'servers' : 'streaming_servers';
        $stmtDns = $pdo->query("SELECT * FROM $tabela_servidores ORDER BY id ASC LIMIT 1");
        $serverInfo = $stmtDns->fetch(PDO::FETCH_ASSOC);
        if ($serverInfo) {
            $dns_val = '';
            if (isset($serverInfo['domain_name']) && !empty(trim($serverInfo['domain_name']))) $dns_val = trim($serverInfo['domain_name']);
            elseif (isset($serverInfo['server_ip']) && !empty(trim($serverInfo['server_ip']))) $dns_val = trim($serverInfo['server_ip']);
            
            if (!empty($dns_val)) {
                if (strpos($dns_val, 'http') !== 0) $dns_val = "http://" . $dns_val;
                $url_streaming = rtrim($dns_val, '/');
            }
        }
    } catch(Exception $e){}
}

// PRÉ-CARREGA CATEGORIAS PARA EVITAR ERROS NO XUI ONE E DEIXAR SUPER RÁPIDO
$categorias = [];
try {
    $stmtCats = $pdo->query("SELECT id, category_name FROM $tabela_categorias");
    while($c = $stmtCats->fetch(PDO::FETCH_ASSOC)) {
        $categorias[$c['id']] = str_replace('"', '', $c['category_name']);
    }
} catch(Exception $e){}

function getNomeCategoria($cat_id_raw, $lista_cats) {
    $c_id = preg_replace('/[^0-9]/', '', $cat_id_raw);
    return $lista_cats[$c_id] ?? 'Sem Categoria';
}

// --- HEADERS PARA DESBLOQUEAR DOWNLOAD E COMPATIBILIDADE ---
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET");
header("Content-Type: application/x-mpegurl; charset=utf-8");
header('Content-Disposition: attachment; filename="lista.m3u"');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');

ob_clean();

echo "#EXTM3U\n";
echo "#EXT-X-SESSION-DATA:DATA-ID=\"com.koffice.xtream.4.0.8\"\n";
@ob_flush(); flush(); // Envia o topo para o aplicativo reconhecer rápido e não dar timeout

// O SEGREDO ESTÁ AQUI: Desliga o buffer do MySQL para não travar o PHP
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

// ====================================================================
// 1. CANAIS E FILMES (Streams Diretas)
// ====================================================================
try {
    $stmtLive = $pdo->query("SELECT id, stream_display_name, stream_icon, category_id, type, target_container FROM streams WHERE type IN (1, 2, 3, 4)");
    
    if ($stmtLive) {
        while ($row = $stmtLive->fetch(PDO::FETCH_ASSOC)) {
            // TRAVA DE BOUQUET: Pula a linha se o stream não estiver no pacote do cliente
            if (!empty($cliente['bouquet']) && !isset($allowed_streams[$row['id']])) { continue; }

            $name = str_replace('"', '', $row['stream_display_name']);
            $icon = $row['stream_icon'];
            $cat  = getNomeCategoria($row['category_id'], $categorias);
            
            echo '#EXTINF:-1 tvg-logo="'.$icon.'" group-title="'.$cat.'",'.$name."\n";
            
            if ($row['type'] == 2) { 
                $ext_v = trim(str_replace(['[', ']', '"'], '', $row['target_container'] ?? 'mp4')) ?: "mp4";
                $ext = "." . $ext_v;
                $pasta_xtream = "movie";
            } else { 
                $ext = ($output === 'm3u8') ? ".m3u8" : ".ts"; 
                $pasta_xtream = "live";
            }

            if ($usar_token) {
                echo $url_painel . "/play/" . $token_xui . "/" . $row['id'] . $ext . "\n";
            } else {
                // Aqui utiliza o Load Balancer ou Painel de forma inteligente
                echo $url_streaming . "/" . $pasta_xtream . "/" . $username . "/" . $password . "/" . $row['id'] . $ext . "\n";
            }
            
            @ob_flush(); flush(); 
        }
        $stmtLive->closeCursor();
    }
} catch(Exception $e){}

// ====================================================================
// 2. SÉRIES (Dupla checagem blindada com Fallback de Query)
// ====================================================================
try {
    $query_series = "SELECT e.{$col_sort} as sort, s.id as stream_id, s.stream_display_name, s.stream_icon, s.target_container, sr.{$pk_series} as master_series_id, sr.title as series_title, s.category_id 
                     FROM $tabela_episodios e 
                     JOIN streams s ON e.stream_id = s.id 
                     JOIN $tabela_series sr ON e.series_id = sr.{$pk_series}";
                     
    $stmtSeries = $pdo->query($query_series);
    
    if ($stmtSeries) {
        while ($row = $stmtSeries->fetch(PDO::FETCH_ASSOC)) {
            
            // TRAVA DE BOUQUET DUPLA: Verifica na tabela de série ou na tabela de canais (Alguns painéis salvam misturado)
            if (!empty($cliente['bouquet'])) {
                $liberado = false;
                if (isset($allowed_series[$row['master_series_id']])) $liberado = true;
                if (isset($allowed_streams[$row['stream_id']])) $liberado = true;
                
                if (!$liberado) {
                    continue; // Pula se não tiver permissão
                }
            }

            $series_name = str_replace('"', '', $row['series_title']);
            $ep_name = "Ep. ".sprintf("%02d", $row['sort'])." - ".str_replace('"', '', $row['stream_display_name']);
            $full_name = $series_name . " - " . $ep_name;
            
            $icon = $row['stream_icon'];
            $cat  = getNomeCategoria($row['category_id'], $categorias);
            
            $ext_s = trim(str_replace(['[', ']', '"'], '', $row['target_container'] ?? 'mp4')) ?: "mp4";
            $ext_s = "." . $ext_s;
            
            echo '#EXTINF:-1 tvg-logo="'.$icon.'" group-title="'.$cat.'",'.$full_name."\n";
            
            if ($usar_token) {
                echo $url_painel . "/play/" . $token_xui . "/" . $row['stream_id'] . $ext_s . "\n";
            } else {
                // MÁGICA FINAL: Séries agora também usam a URL inteligente (Load Balancer)
                echo $url_streaming . "/series/" . $username . "/" . $password . "/" . $row['stream_id'] . $ext_s . "\n";
            }

            @ob_flush(); flush(); 
        }
        $stmtSeries->closeCursor();
    }
} catch(Exception $e){
    // PLANO B: Se a tabela de categorias da série estiver ligada diferente (Xtream UI antigo)
    try {
        $query_fallback = "SELECT e.{$col_sort} as sort, s.id as stream_id, s.stream_display_name, s.stream_icon, s.target_container, sr.{$pk_series} as master_series_id, sr.title as series_title, sr.category_id 
                           FROM $tabela_episodios e 
                           JOIN streams s ON e.stream_id = s.id 
                           JOIN $tabela_series sr ON e.series_id = sr.{$pk_series}";
                           
        $stmtSeriesFb = $pdo->query($query_fallback);
        if ($stmtSeriesFb) {
            while ($row = $stmtSeriesFb->fetch(PDO::FETCH_ASSOC)) {
                if (!empty($cliente['bouquet'])) {
                    $liberado = false;
                    if (isset($allowed_series[$row['master_series_id']])) $liberado = true;
                    if (isset($allowed_streams[$row['stream_id']])) $liberado = true;
                    if (!$liberado) { continue; }
                }
                
                $series_name = str_replace('"', '', $row['series_title']);
                $ep_name = "Ep. ".sprintf("%02d", $row['sort'])." - ".str_replace('"', '', $row['stream_display_name']);
                $full_name = $series_name . " - " . $ep_name;
                
                $icon = $row['stream_icon'];
                $cat  = getNomeCategoria($row['category_id'], $categorias);
                
                $ext_s = trim(str_replace(['[', ']', '"'], '', $row['target_container'] ?? 'mp4')) ?: "mp4";
                $ext_s = "." . $ext_s;
                
                echo '#EXTINF:-1 tvg-logo="'.$icon.'" group-title="'.$cat.'",'.$full_name."\n";
                
                if ($usar_token) {
                    echo $url_painel . "/play/" . $token_xui . "/" . $row['stream_id'] . $ext_s . "\n";
                } else {
                    echo $url_streaming . "/series/" . $username . "/" . $password . "/" . $row['stream_id'] . $ext_s . "\n";
                }
                @ob_flush(); flush(); 
            }
            $stmtSeriesFb->closeCursor();
        }
    } catch(Exception $ex) {}
}

exit;
?>