<?php
// SPANDAMAN TMDBBASE Xtream-compatible M3U wrapper.
ini_set('memory_limit', '1024M');
ini_set('max_execution_time', '300');
require_once __DIR__ . '/config.php';

error_reporting(0);
set_time_limit(0);

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Range, Origin, Accept, Content-Type, User-Agent');
header('Access-Control-Expose-Headers: Content-Length, Content-Range, Content-Type, Location');
if (strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'OPTIONS') {
    http_response_code(204);
    exit;
}

$expectedUsername = 'base';
$expectedPassword = 'base';
$username = $_GET['username'] ?? '';
$password = $_GET['password'] ?? '';
if ($username !== $expectedUsername || $password !== $expectedPassword) {
    http_response_code(401);
    header('Content-Type: text/plain; charset=utf-8');
    echo "Invalid username or password";
    exit;
}

function spandaman_tmdbbase_base_url() {
    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
    $dir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '/')), '/');
    if ($dir === '/' || $dir === '.') $dir = '';
    return $scheme . '://' . $host . $dir;
}

function spandaman_tmdbbase_json($path) {
    if (!is_file($path)) return array();
    $raw = file_get_contents($path);
    if (is_string($raw) && substr($raw, 0, 3) === "\xEF\xBB\xBF") {
        $raw = substr($raw, 3);
    }
    $data = json_decode($raw, true);
    return is_array($data) ? $data : array();
}

function spandaman_tmdbbase_small_cached_rows($cachePath, $sourcePath, $idKeys, $ids) {
    $cached = spandaman_tmdbbase_json($cachePath);
    if (!empty($cached)) {
        return $cached;
    }
    if (!is_file($sourcePath) || filesize($sourcePath) > 80000000) {
        return array();
    }
    $out = array();
    foreach (spandaman_tmdbbase_json($sourcePath) as $row) {
        if (!is_array($row)) continue;
        foreach ($idKeys as $key) {
            $id = (string)($row[$key] ?? '');
            if ($id !== '' && !empty($ids[$id])) {
                $out[] = $row;
                break;
            }
        }
    }
    return $out;
}

function spandaman_tmdbbase_merge_rows_by_id($primaryRows, $fallbackRows, $idKeys) {
    $out = array();
    $seen = array();
    foreach (array($primaryRows, $fallbackRows) as $rows) {
        if (!is_array($rows)) continue;
        foreach ($rows as $row) {
            if (!is_array($row)) continue;
            $id = '';
            foreach ($idKeys as $key) {
                $candidate = (string)($row[$key] ?? '');
                if ($candidate !== '') {
                    $id = $candidate;
                    break;
                }
            }
            if ($id === '' || !ctype_digit($id) || !empty($seen[$id])) continue;
            $seen[$id] = true;
            $out[] = $row;
        }
    }
    return $out;
}

function spandaman_tmdbbase_vod_rows_for_m3u($playableOnly, $playableMovies) {
    if ($playableOnly) {
        return spandaman_tmdbbase_small_cached_rows(__DIR__ . '/spandaman_playable_vod_rows.json', __DIR__ . '/playlist.json', array('stream_id'), $playableMovies);
    }
    return spandaman_tmdbbase_merge_rows_by_id(
        spandaman_tmdbbase_json(__DIR__ . '/spandaman_playable_vod_rows.json'),
        spandaman_tmdbbase_json(__DIR__ . '/playlist.json'),
        array('stream_id')
    );
}

function spandaman_tmdbbase_safe($value) {
    return str_replace(array('"', "\r", "\n"), array("'", ' ', ' '), trim((string)$value));
}

function spandaman_tmdbbase_group($row, $fallback) {
    if (!empty($row['group'])) return (string)$row['group'];
    if (!empty($row['category_name'])) return (string)$row['category_name'];
    if (!empty($row['category_id'])) return $fallback . ' ' . (string)$row['category_id'];
    return $fallback;
}

function spandaman_tmdbbase_live_group($row) {
    $group = spandaman_tmdbbase_group($row, 'Live');
    if ($group === '' || strcasecmp($group, 'Undefined') === 0) {
        return 'Live';
    }
    if (preg_match('/\b(vod|movie|movies|film|films|series|empty name)\b/i', $group)) {
        return 'Live TV';
    }
    return $group;
}

function spandaman_tmdbbase_category_map($path) {
    $map = array();
    foreach (spandaman_tmdbbase_json($path) as $row) {
        if (isset($row['category_id']) && isset($row['category_name'])) {
            $map[(string)$row['category_id']] = (string)$row['category_name'];
        }
    }
    return $map;
}

function spandaman_tmdbbase_playable_ids($kind) {
    $ids = array();
    $paths = array(__DIR__ . '/spandaman_playable_tmdb_cache.json', __DIR__ . '/channels/spandaman_playable_tmdb_cache.json');
    foreach ($paths as $path) {
        if (!is_file($path)) continue;
        $cache = json_decode(file_get_contents($path), true);
        if (!is_array($cache)) continue;
        foreach ($cache as $key => $entry) {
            if (!is_array($entry)) continue;
            if (($entry['kind'] ?? '') !== $kind) continue;
            $id = preg_replace('/_tmdb_url$/', '', (string)$key);
            if (ctype_digit($id) && !empty($entry['url'])) {
                $ids[$id] = true;
            }
        }
        if (!empty($ids)) break;
    }
    return $ids;
}

function spandaman_tmdbbase_playlist_alias_is_useful($path) {
    if (!is_file($path) || filesize($path) < 64) {
        return false;
    }
    $handle = @fopen($path, 'rb');
    if (!$handle) {
        return false;
    }
    $sample = fread($handle, 1048576);
    fclose($handle);
    return is_string($sample) && strpos($sample, '#EXTINF') !== false;
}

function spandaman_tmdbbase_series_episode_map() {
    static $map = null;
    if ($map !== null) {
        return $map;
    }
    $map = array();
    $paths = array(__DIR__ . '/spandaman_series_episode_map.json', __DIR__ . '/channels/spandaman_series_episode_map.json');
    foreach ($paths as $path) {
        $data = spandaman_tmdbbase_json($path);
        if (!is_array($data)) {
            continue;
        }
        foreach ($data as $episodeId => $entry) {
            if (!ctype_digit((string)$episodeId)) {
                continue;
            }
            $seriesId = '';
            $seasonNum = 1;
            $episodeNum = 1;
            if (is_array($entry)) {
                $seriesId = (string)($entry['series_id'] ?? '');
                $seasonNum = intval($entry['season'] ?? ($entry['season_number'] ?? 1));
                $episodeNum = intval($entry['episode'] ?? ($entry['episode_num'] ?? ($entry['episode_number'] ?? 1)));
            } elseif (is_string($entry) && $entry !== '') {
                $decoded = base64_decode($entry, true);
                if (is_string($decoded) && preg_match('~:(\d+)/season/\d+/episode/\d+~', $decoded, $match)) {
                    $seriesId = $match[1];
                }
                if (is_string($decoded) && preg_match('~/season/(\d+)/episode/(\d+)~', $decoded, $match)) {
                    $seasonNum = intval($match[1]);
                    $episodeNum = intval($match[2]);
                }
            }
            if ($seriesId === '') continue;
            if ($seasonNum <= 0) $seasonNum = 1;
            if ($episodeNum <= 0) $episodeNum = 1;
            if (empty($map[$seriesId])) {
                $map[$seriesId] = array();
            }
            $map[$seriesId][] = array(
                'episode_id' => (string)$episodeId,
                'season' => $seasonNum,
                'episode' => $episodeNum,
            );
        }
        if (!empty($map)) {
            break;
        }
    }
    foreach ($map as $seriesId => $episodes) {
        usort($episodes, function ($a, $b) {
            $seasonCmp = intval($a['season'] ?? 0) <=> intval($b['season'] ?? 0);
            if ($seasonCmp !== 0) return $seasonCmp;
            return intval($a['episode'] ?? 0) <=> intval($b['episode'] ?? 0);
        });
        $map[$seriesId] = $episodes;
    }
    return $map;
}

function spandaman_tmdbbase_verified_adult_ids() {
    $ids = array();
    // Adult host links are short-lived; only expose them in playable-only mode
    // after a fresh verifier writes a marker allowing adult rows for this run.
    if (!is_file(__DIR__ . '/spandaman_allow_verified_adult_playlist.flag')) {
        return $ids;
    }
    $paths = array(__DIR__ . '/spandaman_verified_adult_ids.json', __DIR__ . '/channels/spandaman_verified_adult_ids.json');
    foreach ($paths as $path) {
        if (!is_file($path)) continue;
        $data = json_decode(file_get_contents($path), true);
        if (!is_array($data)) continue;
        $rows = $data['ids'] ?? $data;
        if (!is_array($rows)) continue;
        foreach ($rows as $id) {
            $id = (string)$id;
            if (ctype_digit($id)) {
                $ids[$id] = true;
            }
        }
        if (!empty($ids)) break;
    }
    return $ids;
}

function spandaman_tmdbbase_emit_row($name, $logo, $group, $url) {
    $name = spandaman_tmdbbase_safe($name ?: 'SPANDAMAN');
    $logo = str_replace('"', '%22', trim((string)$logo));
    $group = spandaman_tmdbbase_safe($group ?: 'SPANDAMAN');
    echo '#EXTINF:-1 tvg-id="" tvg-name="' . $name . '" tvg-logo="' . $logo . '" group-title="' . $group . '",' . $name . "\n";
    echo $url . "\n";
}

function spandaman_tmdbbase_extra_verified_rows($playableOnly) {
    $rows = spandaman_tmdbbase_json(__DIR__ . '/spandaman_extra_verified_streams.json');
    if (empty($rows)) {
        $rows = spandaman_tmdbbase_json(__DIR__ . '/channels/spandaman_extra_verified_streams.json');
    }
    if (!is_array($rows)) return array();
    $out = array();
    foreach ($rows as $row) {
        if (!is_array($row)) continue;
        $url = trim((string)($row['url'] ?? ''));
        if ($url === '') continue;
        if ($playableOnly && empty($row['verified'])) continue;
        $out[] = $row;
    }
    return $out;
}

function spandaman_tmdbbase_extra_verified_adult_rows($playableOnly) {
    $rows = spandaman_tmdbbase_json(__DIR__ . '/spandaman_extra_verified_adult_streams.json');
    if (empty($rows)) {
        $rows = spandaman_tmdbbase_json(__DIR__ . '/channels/spandaman_extra_verified_adult_streams.json');
    }
    if (!is_array($rows)) return array();
    $allowed = $playableOnly ? spandaman_tmdbbase_verified_adult_ids() : array();
    $out = array();
    foreach ($rows as $row) {
        if (!is_array($row)) continue;
        $id = (string)($row['id'] ?? ($row['stream_id'] ?? ''));
        $url = trim((string)($row['url'] ?? ''));
        if ($url === '') continue;
        if ($playableOnly && ($id === '' || empty($allowed[$id]))) continue;
        $out[] = $row;
    }
    return $out;
}

function spandaman_tmdbbase_extra_verified_live_rows($playableOnly) {
    $rows = spandaman_tmdbbase_json(__DIR__ . '/spandaman_extra_verified_live_streams.json');
    if (empty($rows)) {
        $rows = spandaman_tmdbbase_json(__DIR__ . '/channels/spandaman_extra_verified_live_streams.json');
    }
    if (!is_array($rows)) return array();
    $out = array();
    foreach ($rows as $row) {
        if (!is_array($row)) continue;
        $id = (string)($row['id'] ?? ($row['stream_id'] ?? ''));
        $url = trim((string)($row['url'] ?? ''));
        if ($id === '' || !ctype_digit($id) || $url === '') continue;
        if ($playableOnly && empty($row['verified'])) continue;
        $out[] = $row;
    }
    return $out;
}

$base = spandaman_tmdbbase_base_url();
$output = strtolower(trim($_GET['output'] ?? 'm3u8'));
// Live output=ts now uses live_play.php + bundled FFmpeg to return real
// MPEG-TS bytes. VOD/series stay on their native hosted routes.
$liveExt = ($output === 'ts') ? 'ts' : 'm3u8';
$vodExt = 'm3u8';
$fullCatalog = isset($_GET['full']) && $_GET['full'] === '1';
$playableOnly = $fullCatalog ? false : true;
if (isset($_GET['playable_only'])) {
    $playableOnly = $_GET['playable_only'] !== '0';
}
$useStaticAlias = $fullCatalog || (!empty($_GET['static']) && $_GET['static'] !== '0');
$playableMovies = $playableOnly ? spandaman_tmdbbase_playable_ids('movie') : array();
$playableSeries = $playableOnly ? spandaman_tmdbbase_playable_ids('series') : array();

if ($useStaticAlias && !$playableOnly && spandaman_tmdbbase_playlist_alias_is_useful(__DIR__ . '/playlist.m3u8')) {
    header('Content-Type: audio/x-mpegurl; charset=utf-8');
    header('Content-Disposition: inline; filename="tmdbbase.m3u8"');
    header('Content-Length: ' . filesize(__DIR__ . '/playlist.m3u8'));
    while (ob_get_level() > 0) {
        @ob_end_clean();
    }
    readfile(__DIR__ . '/playlist.m3u8');
    exit;
}

header('Content-Type: audio/x-mpegurl; charset=utf-8');
header('Content-Disposition: inline; filename="tmdbbase.m3u8"');
while (ob_get_level() > 0) {
    @ob_end_clean();
}
echo '#EXTM3U x-tvg-url="' . $base . '/xmltv.php?username=base&password=base" url-tvg="' . $base . '/xmltv.php?username=base&password=base"' . "\n";

$liveCategories = spandaman_tmdbbase_category_map(__DIR__ . '/channels/get_live_categories.json');
foreach (spandaman_tmdbbase_extra_verified_live_rows($playableOnly) as $row) {
    spandaman_tmdbbase_emit_row(
        $row['name'] ?? '',
        $row['logo'] ?? ($row['stream_icon'] ?? ''),
        spandaman_tmdbbase_live_group($row),
        $base . '/live/base/base/' . (string)($row['id'] ?? ($row['stream_id'] ?? '0')) . '.' . $liveExt
    );
}
if (!$playableOnly) {
    foreach (spandaman_tmdbbase_json(__DIR__ . '/channels/live_playlist.json') as $row) {
        $id = intval($row['stream_id'] ?? 0);
        if ($id <= 0) continue;
        $categoryId = (string)($row['category_id'] ?? '');
        spandaman_tmdbbase_emit_row(
            $row['name'] ?? '',
            $row['stream_icon'] ?? '',
            $liveCategories[$categoryId] ?? spandaman_tmdbbase_live_group($row),
            $base . '/live/base/base/' . $id . '.' . $liveExt
        );
    }
}

foreach (spandaman_tmdbbase_vod_rows_for_m3u($playableOnly, $playableMovies) as $row) {
    $id = intval($row['stream_id'] ?? 0);
    if ($id <= 0) continue;
    if ($playableOnly && empty($playableMovies[(string)$id])) continue;
    spandaman_tmdbbase_emit_row(
        $row['name'] ?? '',
        $row['stream_icon'] ?? '',
        spandaman_tmdbbase_group($row, 'VOD'),
        $base . '/movie/base/base/' . $id . '.' . $vodExt
    );
}

$verifiedAdultIds = $playableOnly ? spandaman_tmdbbase_verified_adult_ids() : array();
foreach (spandaman_tmdbbase_json(__DIR__ . '/adult-movies.json') as $row) {
    $idRaw = (string)($row['stream_id'] ?? '');
    $id = intval($idRaw);
    if ($id <= 0) continue;
    if ($playableOnly && empty($verifiedAdultIds[$idRaw])) continue;
    spandaman_tmdbbase_emit_row(
        $row['name'] ?? '',
        $row['stream_icon'] ?? '',
        'XXX Adult Movies',
        $base . '/movie/base/base/' . $id . '.mp4'
    );
}

foreach (spandaman_tmdbbase_extra_verified_adult_rows($playableOnly) as $row) {
    spandaman_tmdbbase_emit_row(
        $row['name'] ?? '',
        $row['logo'] ?? ($row['stream_icon'] ?? ''),
        $row['group'] ?? 'XXX Adult Movies',
        $base . '/movie/base/base/' . (string)($row['id'] ?? ($row['stream_id'] ?? '0')) . '.mp4'
    );
}

foreach ($playableOnly ? spandaman_tmdbbase_small_cached_rows(__DIR__ . '/spandaman_playable_series_rows.json', __DIR__ . '/tv_playlist.json', array('series_id', 'stream_id'), $playableSeries) : spandaman_tmdbbase_json(__DIR__ . '/tv_playlist.json') as $row) {
    $id = intval($row['series_id'] ?? ($row['stream_id'] ?? 0));
    if ($id <= 0) continue;
    $episodeMap = spandaman_tmdbbase_series_episode_map();
    $episodes = $episodeMap[(string)$id] ?? array();
    if (empty($episodes) || !is_array($episodes)) {
        continue;
    }
    foreach ($episodes as $episode) {
        if (!is_array($episode)) continue;
        $episodeId = (string)($episode['episode_id'] ?? '');
        if ($episodeId === '') continue;
        $seasonNum = max(1, intval($episode['season'] ?? 1));
        $episodeNum = max(1, intval($episode['episode'] ?? 1));
        $suffix = sprintf(' S%02dE%02d', $seasonNum, $episodeNum);
        spandaman_tmdbbase_emit_row(
            ($row['name'] ?? 'Series') . $suffix,
            $row['cover'] ?? ($row['stream_icon'] ?? ''),
            spandaman_tmdbbase_group($row, 'Series'),
            $base . '/series/base/base/' . $episodeId . '.m3u8'
        );
    }
}

foreach (spandaman_tmdbbase_extra_verified_rows($playableOnly) as $idx => $row) {
    $kind = (string)($row['kind'] ?? 'vod');
    $rowId = (string)($row['id'] ?? ($row['stream_id'] ?? ''));
    $url = '';
    if ($kind === 'series') {
        $seriesId = intval($row['id'] ?? (900000001 + intval($idx)));
        if ($seriesId < 900000001) {
            $seriesId = 900000001 + intval($idx);
        }
        $url = $base . '/series/base/base/' . $seriesId . '.m3u8';
    } elseif ($kind === 'vod' || $kind === 'movie' || $kind === '') {
        if ($rowId === '' || !ctype_digit($rowId)) {
            $rowId = (string)(890000001 + intval($idx));
        }
        $url = $base . '/movie/base/base/' . $rowId . '.m3u8';
    } else {
        $url = $row['url'] ?? '';
    }
    spandaman_tmdbbase_emit_row(
        $row['name'] ?? '',
        $row['logo'] ?? ($row['stream_icon'] ?? ''),
        $row['group'] ?? 'Verified Extra',
        $url
    );
}
?>
