<?php
function ugfx_read_json(string $path, $default = []) {
    if (!file_exists($path)) return $default;
    $data = json_decode(file_get_contents($path), true);
    return is_array($data) ? $data : $default;
}

function ugfx_write_json(string $path, $data): bool {
    $dir = dirname($path);
    if (!is_dir($dir)) mkdir($dir, 0775, true);
    return (bool) file_put_contents($path, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
}

function ugfx_asset(string $path): string {
    return 'assets/' . ltrim($path, '/');
}

function ugfx_vendor_asset(string $localPath, string $cdnUrl, string $prefix = ''): string {
    $normalized = ltrim($localPath, '/');
    $absolute = dirname(__DIR__) . '/' . $normalized;
    if (file_exists($absolute)) {
        return $prefix . $normalized;
    }
    return $cdnUrl;
}

function ugfx_is_active(string $page, string $current): string {
    return $page === $current ? 'active' : '';
}

function ugfx_slugify(string $text): string {
    $text = strtolower(trim($text));
    $text = preg_replace('/[^a-z0-9]+/', '-', $text);
    return trim($text ?? '', '-') ?: 'page';
}

function ugfx_strlen(string $text): int {
    return function_exists('mb_strlen') ? mb_strlen($text) : strlen($text);
}

function ugfx_substr(string $text, int $start, ?int $length = null): string {
    if (function_exists('mb_substr')) {
        return $length === null ? mb_substr($text, $start) : mb_substr($text, $start, $length);
    }
    return $length === null ? substr($text, $start) : substr($text, $start, $length);
}

function ugfx_excerpt(string $text, int $length = 180): string {
    $text = trim(strip_tags($text));
    return ugfx_strlen($text) > $length ? ugfx_substr($text, 0, $length - 1) . '…' : $text;
}

function ugfx_sort_items_by_date_desc(array $items): array {
    usort($items, function ($a, $b) {
        return strtotime((string)($b['start'] ?? $b['date'] ?? '')) <=> strtotime((string)($a['start'] ?? $a['date'] ?? ''));
    });
    return $items;
}

function ugfx_get_news(int $limit = 6): array {
    global $ugfx;
    $items = ugfx_read_json($ugfx['storage']['news'], []);
    $items = array_values(array_filter($items, function ($item) { return ($item['published'] ?? 0) == 1; }));
    return array_slice($items, 0, $limit);
}

function ugfx_get_events(int $limit = 4): array {
    global $ugfx;
    $items = ugfx_read_json($ugfx['storage']['events'], []);
    $items = array_values(array_filter($items, function ($item) { return ($item['published'] ?? 0) == 1; }));
    $items = ugfx_sort_items_by_date_desc($items);
    return array_slice($items, 0, $limit);
}

function ugfx_get_djs(int $limit = 8): array {
    global $ugfx;
    return array_slice(ugfx_read_json($ugfx['storage']['djs'], []), 0, $limit);
}

function ugfx_get_top50(int $limit = 10): array {
    global $ugfx;
    $items = ugfx_read_json($ugfx['storage']['top50'], []);
    uasort($items, function ($a, $b) { return ($b['count'] ?? 0) <=> ($a['count'] ?? 0); });
    return array_slice($items, 0, $limit, true);
}

function ugfx_get_schedule(): array {
    global $ugfx;
    return ugfx_read_json($ugfx['storage']['schedule'], []);
}

function ugfx_get_friends(int $limit = 12): array {
    global $ugfx;
    return array_slice(ugfx_read_json($ugfx['storage']['friends'], []), 0, $limit);
}

function ugfx_get_pages(bool $publishedOnly = true): array {
    global $ugfx;
    $items = ugfx_read_json($ugfx['storage']['pages'], []);
    if ($publishedOnly) {
        $items = array_values(array_filter($items, function ($item) { return ($item['published'] ?? 0) == 1; }));
    }
    return $items;
}

function ugfx_get_page_by_slug(string $slug): ?array {
    foreach (ugfx_get_pages(false) as $page) {
        if (($page['slug'] ?? '') === $slug) {
            return $page;
        }
    }
    return null;
}

function ugfx_day_name(?int $timestamp = null): string {
    return date('l', $timestamp ?? time());
}

function ugfx_current_show(): array {
    $schedule = ugfx_get_schedule();
    $day = ugfx_day_name();
    $hour = (int) date('G');
    $current = $schedule[$day][$hour] ?? 'Underground FX Live';
    $next = $schedule[$day][($hour + 1) % 24] ?? 'Underground FX Live';
    return ['day' => $day, 'hour' => $hour, 'current' => $current, 'next' => $next];
}


function ugfx_fetch_with_basic_auth(array $urls, string $user, string $pass): string {
    foreach ($urls as $url) {
        $url = trim((string)$url);
        if ($url === '') continue;

        if (function_exists('curl_init')) {
            $ch = curl_init($url);
            curl_setopt_array($ch, [
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
                CURLOPT_USERPWD => $user . ':' . $pass,
                CURLOPT_TIMEOUT => 6,
                CURLOPT_CONNECTTIMEOUT => 4,
                CURLOPT_FAILONERROR => false,
                CURLOPT_HTTPHEADER => ['Accept: application/xml, text/xml, text/html, */*'],
            ]);
            $raw = curl_exec($ch);
            $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            if (is_string($raw) && trim($raw) !== '' && $code < 400) {
                return $raw;
            }
        }

        $context = stream_context_create([
            'http' => [
                'timeout' => 6,
                'ignore_errors' => true,
                'header' => "Authorization: Basic " . base64_encode($user . ':' . $pass) . "\r\n" .
                            "Accept: application/xml, text/xml, text/html, */*\r\n"
            ]
        ]);
        $raw = @file_get_contents($url, false, $context);
        if (is_string($raw) && trim($raw) !== '') {
            return $raw;
        }
    }
    return '';
}

function ugfx_parse_stats_xsl(string $html): array {
    $result = [
        'listener_connections' => 0,
        'listeners' => 0,
        'mount' => '/autodj',
        'mount_listeners' => 0,
        'server_name' => 'Underground FX AutoDJ',
        'title' => '',
    ];

    $plain = html_entity_decode(strip_tags($html), ENT_QUOTES, 'UTF-8');
    $plain = preg_replace('/\s+/', ' ', $plain);

    if (preg_match('/listener_connections\s+([0-9,]+)/i', $plain, $m)) {
        $result['listener_connections'] = (int) str_replace(',', '', $m[1]);
    }
    if (preg_match('/\blisteners\s+([0-9,]+)/i', $plain, $m)) {
        $result['listeners'] = (int) str_replace(',', '', $m[1]);
    }

    $section = $plain;
    if (preg_match('/Mountpoint\s+(\/autodj)([\s\S]*?)(?:Mountpoint\s+\/stream|Mount Authentication|$)/i', $plain, $sec)) {
        $section = $sec[0];
        $result['mount'] = '/autodj';
    }

    if (preg_match('/x_icy_title\s+([^\r\n]+?)(?:\s+(?:x_icy_url|Playlist|Mount Authentication|content-type)\b|$)/i', $section, $m)) {
        $result['title'] = trim($m[1]);
    }
    if (preg_match('/server_name\s+([^\r\n]+?)(?:\s+(?:server_type|server_url|slow_listeners|source_ip)\b|$)/i', $section, $m)) {
        $result['server_name'] = trim($m[1]);
    }
    if (preg_match('/Mountpoint\s+\/autodj[\s\S]*?\blisteners\s+([0-9,]+)/i', $section, $m)) {
        $result['mount_listeners'] = (int) str_replace(',', '', $m[1]);
    } elseif (preg_match('/\blisteners\s+([0-9,]+)/i', $section, $m)) {
        $result['mount_listeners'] = (int) str_replace(',', '', $m[1]);
    }

    return $result;
}


function ugfx_fetch_icy_title(string $streamUrl): string {
    $parts = @parse_url($streamUrl);
    if (!$parts || empty($parts['host'])) return '';
    $scheme = strtolower((string)($parts['scheme'] ?? 'http'));
    $host = (string)$parts['host'];
    $port = (int)($parts['port'] ?? ($scheme === 'https' ? 443 : 80));
    $path = ($parts['path'] ?? '/') . (!empty($parts['query']) ? '?' . $parts['query'] : '');
    $transport = $scheme === 'https' ? 'ssl://' : '';
    $fp = @fsockopen($transport . $host, $port, $errno, $errstr, 4);
    if (!$fp) return '';
    stream_set_timeout($fp, 4);
    $out = "GET {$path} HTTP/1.0\r\nHost: {$host}\r\nIcy-MetaData: 1\r\nUser-Agent: UGFXNowPlaying/1.0\r\nConnection: close\r\n\r\n";
    fwrite($fp, $out);
    $metaInt = 0;
    while (!feof($fp)) {
        $line = fgets($fp, 512);
        if ($line === false) break;
        $trim = trim($line);
        if ($trim === '') break;
        if (stripos($trim, 'icy-metaint:') === 0) {
            $metaInt = (int)trim(substr($trim, 12));
        }
    }
    if ($metaInt <= 0) { fclose($fp); return ''; }
    $audio = '';
    while (strlen($audio) < $metaInt && !feof($fp)) {
        $audio .= fread($fp, $metaInt - strlen($audio));
    }
    $len = ord(fread($fp, 1)) * 16;
    $metadata = $len > 0 ? fread($fp, $len) : '';
    fclose($fp);
    if (preg_match("/StreamTitle='([^']*)';/i", (string)$metadata, $mm)) {
        return html_entity_decode(trim($mm[1]), ENT_QUOTES, 'UTF-8');
    }
    return '';
}

function ugfx_get_player_urls(): array {
    $settings = ugfx_read_json(__DIR__ . '/../data/settings.json', []);
    $rawUrl = trim((string)($settings['public_stream_url'] ?? 'http://radio.undergroundfxradio.com:9000/stream'));
    $proxyBase = '/stream-proxy.php';
    return [
        'raw' => $rawUrl,
        'proxy' => $proxyBase,
        'preferred' => $proxyBase,
        'using_proxy' => true,
    ];
}

function ugfx_icecast_status(): array {
    static $cached = null;
    if ($cached !== null) {
        return $cached;
    }

    $settings = ugfx_read_json(__DIR__ . '/../data/settings.json', []);
    $statsUrl = $settings['stats_url'] ?? 'http://cr2.broadcasturself.com:9000/admin/stats';
    $statsXslUrl = $settings['stats_xsl_url'] ?? 'http://cr2.broadcasturself.com:9000/admin/stats.xsl?showall=true';
    $user = $settings['stats_user'] ?? 'UndergroundFx';
    $pass = $settings['stats_password'] ?? 'TxHL7RqdSjQbSB';
    $playerUrls = ugfx_get_player_urls();
    $publicStream = trim((string)($playerUrls['raw'] ?? 'http://radio.undergroundfxradio.com:9000/stream'));

    $fallback = [
        'server_listeners' => 0,
        'current_listeners' => 0,
        'title' => 'Underground FX Live',
        'artist' => 'AutoDJ',
        'mount' => '/autodj',
        'stream_url' => $playerUrls['preferred'],
        'public_stream_url' => $publicStream,
        'direct_stream_url' => $publicStream,
        'status' => 'LIVE'
    ];

    $cacheFile = __DIR__ . '/../data/icecast_stats_cache.json';
    $cacheTtl = 15;
    if (is_file($cacheFile) && (time() - (int)filemtime($cacheFile) <= $cacheTtl)) {
        $cachedData = json_decode((string)@file_get_contents($cacheFile), true);
        if (is_array($cachedData) && array_key_exists('server_listeners', $cachedData)) {
            return $cached = $cachedData;
        }
    }

    $data = null;

    $html = ugfx_fetch_with_basic_auth([$statsXslUrl], $user, $pass);
    if ($html !== '') {
        $parsed = ugfx_parse_stats_xsl($html);
        $artist = $parsed['server_name'] ?: 'AutoDJ';
        $title = $parsed['title'] ?: '';
        if (strpos($title, ' - ') !== false) {
            list($artistPart, $titlePart) = array_map('trim', explode(' - ', $title, 2));
            if ($artistPart !== '') $artist = $artistPart;
            if ($titlePart !== '') $title = $titlePart;
        }
        $data = [
            'server_listeners' => (int)$parsed['listener_connections'],
            'current_listeners' => (int)$parsed['mount_listeners'],
            'title' => $title,
            'artist' => $artist,
            'mount' => $parsed['mount'] ?: '/autodj',
            'stream_url' => $playerUrls['preferred'],
            'public_stream_url' => $publicStream,
            'direct_stream_url' => $publicStream,
            'status' => 'LIVE'
        ];
    }

    $raw = ugfx_fetch_with_basic_auth([$statsUrl, 'http://cr2.broadcasturself.com:9000/admin/stats', 'http://cr2.broadcasturself.com:9000/admin/stats.xml'], $user, $pass);
    if ($raw !== '') {
        $xml = @simplexml_load_string($raw);
        if ($xml) {
            $mount = null;
            if (isset($xml->source)) {
                foreach ($xml->source as $source) {
                    $mountName = (string)($source['mount'] ?? '');
                    if ($mountName === '/autodj') {
                        $mount = $source;
                        break;
                    }
                }
                if ($mount === null && isset($xml->source[0])) {
                    $mount = $xml->source[0];
                }
            }

            $rawTitle = trim((string)($mount->title ?? ''));
            if ($rawTitle === '' && isset($mount->x_icy_title)) {
                $rawTitle = trim((string)$mount->x_icy_title);
            }
            if ($rawTitle === '' && isset($mount->metadata->x_icy_title)) {
                $rawTitle = trim((string)$mount->metadata->x_icy_title);
            }

            $artist = trim((string)($mount->server_name ?? 'Underground FX AutoDJ'));
            $title = $rawTitle;
            if (strpos($title, ' - ') !== false) {
                list($artistPart, $titlePart) = array_map('trim', explode(' - ', $title, 2));
                if ($artistPart !== '') $artist = $artistPart;
                if ($titlePart !== '') $title = $titlePart;
            }

            $dataFromXml = [
                'server_listeners' => (int)($xml->listener_connections ?? $xml->listeners ?? 0),
                'current_listeners' => (int)($mount->listeners ?? $xml->listeners ?? 0),
                'title' => $title,
                'artist' => $artist,
                'mount' => (string)($mount['mount'] ?? '/autodj'),
                'stream_url' => $playerUrls['preferred'],
                'public_stream_url' => $publicStream,
                'direct_stream_url' => $publicStream,
                'status' => 'LIVE'
            ];

            if ($data === null || (!empty($dataFromXml['server_listeners']) || !empty($dataFromXml['title']))) {
                $data = $dataFromXml;
            }
        }
    }

    $icyTitle = ugfx_fetch_icy_title($publicStream);
    if ($icyTitle !== '') {
        $artist = $data['artist'] ?? 'AutoDJ';
        $title = $icyTitle;
        if (strpos($icyTitle, ' - ') !== false) {
            list($artistPart, $titlePart) = array_map('trim', explode(' - ', $icyTitle, 2));
            if ($artistPart !== '') $artist = $artistPart;
            if ($titlePart !== '') $title = $titlePart;
        }
        if ($data === null) {
            $data = $fallback;
        }
        $data['title'] = $title;
        $data['artist'] = $artist;
    }

    if ($data === null) {
        if (is_file($cacheFile)) {
            $stale = json_decode((string)@file_get_contents($cacheFile), true);
            if (is_array($stale)) {
                return $cached = $stale;
            }
        }
        return $cached = $fallback;
    }

    if (empty($data['title'])) $data['title'] = 'Underground FX Live';
    if (empty($data['artist'])) $data['artist'] = 'AutoDJ';
    if (!isset($data['stream_url'])) $data['stream_url'] = $playerUrls['preferred'];
    if (!isset($data['public_stream_url'])) $data['public_stream_url'] = $publicStream;
    if (!isset($data['direct_stream_url'])) $data['direct_stream_url'] = $publicStream;

    @file_put_contents($cacheFile, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), LOCK_EX);
    return $cached = $data;
}

function ugfx_now_playing(): array {
    $show = ugfx_current_show();
    $icecast = ugfx_icecast_status();
    return [
        'title' => $icecast['title'] ?: 'Underground FX Live',
        'artist' => $icecast['artist'] ?: $show['current'],
        'album' => 'Underground FX Radio',
        'art' => ugfx_asset('img/brand/ugfx-hero.png'),
        'listeners' => $icecast['server_listeners'],
        'current_listeners' => $icecast['current_listeners'],
        'status' => $icecast['status'],
        'mount' => $icecast['mount'],
        'stream_url' => $icecast['stream_url'],
        'public_stream_url' => $icecast['public_stream_url'] ?? '',
        'direct_stream_url' => $icecast['direct_stream_url'] ?? ''
    ];
}

function ugfx_nav_items(): array {
    return [
        ['label' => 'Home', 'href' => 'index.php'],
        ['label' => 'Listen Live', 'href' => 'listen-live.php'],
        ['label' => 'Schedule', 'href' => 'schedule.php'],
        ['label' => 'Requests', 'href' => 'requests.php'],
        ['label' => 'News', 'href' => 'news.php'],
        ['label' => 'Events', 'href' => 'events.php'],
        ['label' => 'Team', 'href' => 'team.php'],
        ['label' => 'Join', 'href' => 'join.php'],
        ['label' => 'Friends', 'href' => 'friends.php'],
        ['label' => 'Chat', 'href' => 'chat.php'],
        ['label' => 'Contact', 'href' => 'contact.php'],
    ];
}

function ugfx_safe_links(string $text): string {
    $escaped = nl2br(htmlspecialchars($text, ENT_QUOTES, 'UTF-8'));
    return preg_replace_callback('/(https?:\/\/[^\s<]+)/i', function ($matches) {
        $url = htmlspecialchars($matches[1], ENT_QUOTES, 'UTF-8');
        return '<a href="' . $url . '" target="_blank" rel="noopener noreferrer nofollow">' . $url . '</a>';
    }, $escaped);
}

function ugfx_chat_messages(): array {
    global $ugfx;
    return ugfx_read_json($ugfx['storage']['chat'], []);
}

function ugfx_chat_add(array $message): bool {
    global $ugfx;
    $messages = ugfx_chat_messages();
    $message['id'] = time() . rand(100,999);
    $messages[] = $message;
    return ugfx_write_json($ugfx['storage']['chat'], array_slice($messages, -200));
}

function ugfx_banned_words(): array {
    global $ugfx;
    return ugfx_read_json($ugfx['storage']['banned_words'], []);
}

function ugfx_contains_banned_word(string $message): bool {
    foreach (ugfx_banned_words() as $word) {
        if ($word !== '' && stripos($message, $word) !== false) return true;
    }
    return false;
}

function ugfx_require_admin(): void {
    if (empty($_SESSION['ugfx_admin'])) {
        header('Location: login.php');
        exit;
    }
}

function ugfx_admin_attempt(string $username, string $password): bool {
    global $ugfx;
    $users = ugfx_read_json($ugfx['storage']['users'], []);
    foreach ($users as $user) {
        if (($user['username'] ?? '') === $username && ($user['password'] ?? '') === $password) {
            $_SESSION['ugfx_admin'] = $user;
            return true;
        }
    }
    return false;
}
?>
