<?php
session_start();
require __DIR__ . '/auth.php';
require __DIR__ . '/includes/admin_lib.php';
if (!(isset($CAN_VIEW) ? $CAN_VIEW : true)) { http_response_code(403); echo '<h1>Access Denied</h1>'; exit; }
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !$CAN_EDIT) { smurf_admin_denied('You do not have permission to use File Finder controls.'); }

$settingsFile = __DIR__ . '/../data/file_finder_settings.json';
$downloadDir  = __DIR__ . '/downloads';
$downloadUrlBase = 'downloads';
if (!is_dir($downloadDir)) {
    @mkdir($downloadDir, 0755, true);
}

$defaults = [
    'freesound_api_key' => '',
    'max_results' => 24,
    'max_download_size_mb' => 3072,
    'allow_youtube_search' => true,
    'enable_internet_archive' => true,
    'enable_wikimedia_commons' => true,
    'enable_freesound' => true,
    'enable_direct_file_downloads' => true,
    'debug_mode' => false,
    'external_tool_label' => 'Open External Link',
    'external_tool_url' => '',
    'allowed_domains' => [
        'archive.org',
        'upload.wikimedia.org',
        'freesound.org',
        'cdn.freesound.org',
        'creativecommons.org',
    ],
    'allowed_extensions' => [
        'jpg','jpeg','png','gif','webp','bmp','svg',
        'mp3','wav','ogg','aac','flac','m4a',
        'mp4','m4v','webm','mov','avi','mkv','wmv','flv',
        'pdf','zip','rar','7z','txt','csv','json'
    ],
];

function ff_load_settings($file, $defaults) {
    if (!is_file($file)) return $defaults;
    $json = @file_get_contents($file);
    $data = json_decode((string)$json, true);
    if (!is_array($data)) return $defaults;
    $merged = $defaults;
    foreach ($data as $k => $v) {
        $merged[$k] = $v;
    }
    if (!is_array($merged['allowed_domains'] ?? null)) {
        $merged['allowed_domains'] = $defaults['allowed_domains'];
    }
    if (!is_array($merged['allowed_extensions'] ?? null)) {
        $merged['allowed_extensions'] = $defaults['allowed_extensions'];
    }
    return $merged;
}

function ff_save_settings($file, $settings) {
    @file_put_contents($file, json_encode($settings, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
}

$config = ff_load_settings($settingsFile, $defaults);

$ffDebugLog = [];

function ff_debug($message, $context = []) {
    global $ffDebugLog, $config;
    if (empty($config['debug_mode'])) return;
    $line = (string)$message;
    if ($context) {
        $json = json_encode($context, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        if ($json !== false && $json !== '[]') $line .= ' :: ' . $json;
    }
    $ffDebugLog[] = $line;
}

function ff_get_debug_log() {
    global $ffDebugLog;
    return $ffDebugLog;
}

function esc($value) { return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); }

function normalizeUrl($url) {
    $url = trim((string)$url);
    if ($url === '' || !filter_var($url, FILTER_VALIDATE_URL)) return false;
    $parts = parse_url($url);
    if (!$parts || empty($parts['scheme']) || empty($parts['host'])) return false;
    $scheme = strtolower($parts['scheme']);
    if (!in_array($scheme, ['http', 'https'], true)) return false;
    return $url;
}

function getHost($url) {
    return strtolower((string)parse_url((string)$url, PHP_URL_HOST));
}

function hostAllowed($url, array $allowedDomains) {
    $host = getHost($url);
    if ($host === '') return false;
    foreach ($allowedDomains as $domain) {
        $domain = strtolower(trim((string)$domain));
        if ($domain === '') continue;
        if ($host === $domain || str_ends_with($host, '.' . $domain)) return true;
    }
    return false;
}

function getExtensionFromUrl($url) {
    $path = (string)parse_url((string)$url, PHP_URL_PATH);
    return strtolower((string)pathinfo($path, PATHINFO_EXTENSION));
}

function extensionAllowed($url, array $allowedExtensions) {
    $ext = getExtensionFromUrl($url);
    return $ext !== '' && in_array($ext, $allowedExtensions, true);
}

function safeFilenameFromUrl($url) {
    $path = (string)parse_url((string)$url, PHP_URL_PATH);
    $filename = basename($path);
    if ($filename === '' || $filename === '/' || $filename === '.') {
        $filename = 'file_' . date('Ymd_His');
    }
    $filename = preg_replace('/[^A-Za-z0-9._-]/', '_', $filename);
    if (strlen($filename) > 180) {
        $ext = pathinfo($filename, PATHINFO_EXTENSION);
        $name = pathinfo($filename, PATHINFO_FILENAME);
        $name = substr($name, 0, 160);
        $filename = $ext ? $name . '.' . $ext : $name;
    }
    return $filename;
}

function logLine($file, $line) {
    @file_put_contents($file, '[' . date('Y-m-d H:i:s') . '] ' . $line . PHP_EOL, FILE_APPEND);
}

function httpRequest($url, $userAgent, $timeout, $extraHeaders = [], $method = 'GET') {
    if (!function_exists('curl_init')) {
        ff_debug('cURL extension missing', ['url' => $url, 'method' => $method]);
        return ['ok' => false, 'error' => 'cURL extension missing', 'errno' => -1, 'status' => 0, 'final_url' => $url];
    }
    $ch = curl_init($url);
    $headers = array_merge([
        'User-Agent: ' . $userAgent,
        'Accept: */*'
    ], $extraHeaders);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5,
        CURLOPT_TIMEOUT => $timeout,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_HEADER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_ENCODING => '',
    ]);
    if (strtoupper($method) === 'HEAD') {
        curl_setopt($ch, CURLOPT_NOBODY, true);
    }
    $raw = curl_exec($ch);
    $err = curl_error($ch);
    $errno = curl_errno($ch);
    $info = curl_getinfo($ch);
    curl_close($ch);
    if ($raw === false) {
        ff_debug('HTTP request failed', ['url' => $url, 'method' => $method, 'errno' => $errno, 'error' => $err ?: 'Request failed']);
        return ['ok' => false, 'error' => $err ?: 'Request failed', 'errno' => $errno, 'status' => (int)($info['http_code'] ?? 0), 'final_url' => $info['url'] ?? $url];
    }
    $headerSize = $info['header_size'] ?? 0;
    $result = [
        'ok' => true,
        'status' => $info['http_code'] ?? 0,
        'content_type' => $info['content_type'] ?? '',
        'final_url' => $info['url'] ?? $url,
        'headers_raw' => substr($raw, 0, $headerSize),
        'body' => substr($raw, $headerSize),
        'download_size' => strlen(substr($raw, $headerSize)),
        'errno' => $errno,
    ];
    if ((int)($result['status'] ?? 0) >= 400) {
        ff_debug('HTTP request returned error status', ['url' => $url, 'method' => $method, 'status' => (int)$result['status'], 'final_url' => $result['final_url'], 'content_type' => $result['content_type']]);
    }
    return $result;
}

function parseHeaderValue($headersRaw, $headerName) {
    foreach (preg_split("/\r\n|\n|\r/", (string)$headersRaw) as $line) {
        if (stripos($line, $headerName . ':') === 0) {
            return trim(substr($line, strlen($headerName) + 1));
        }
    }
    return '';
}

function dedupeResults(array $rows) {
    $out = [];
    $seen = [];
    foreach ($rows as $row) {
        $key = trim((string)($row['url'] ?? '')) . '|' . trim((string)($row['download_url'] ?? ''));
        if ($key === '|' || isset($seen[$key])) continue;
        $seen[$key] = true;
        $out[] = $row;
    }
    return $out;
}

function resultRow($title, $url, $source, $desc, $mode, $downloadUrl = '', $note = '', $thumb = '') {
    return [
        'title' => (string)$title,
        'url' => (string)$url,
        'source' => (string)$source,
        'description' => (string)$desc,
        'mode' => (string)$mode,
        'download_url' => (string)$downloadUrl,
        'note' => (string)$note,
        'thumb' => (string)$thumb,
    ];
}

function searchInternetArchive($query, $mediaType, $config) {
    if (empty($config['enable_internet_archive'])) return ['ok' => true, 'results' => []];
    ff_debug('Internet Archive search start', ['query' => $query, 'mediaType' => $mediaType]);
    $q = '(' . $query . ')';
    if ($mediaType === 'audio') $q .= ' AND mediatype:(audio)';
    if ($mediaType === 'video') $q .= ' AND mediatype:(movies)';
    if ($mediaType === 'image') $q .= ' AND mediatype:(image)';
    $url = 'https://archive.org/advancedsearch.php?q=' . rawurlencode($q)
        . '&fl[]=identifier&fl[]=title&fl[]=mediatype&rows=' . (int)$config['max_results'] . '&page=1&output=json';
    $resp = httpRequest($url, 'BroadcastUrSelfFileFinder/2.0', 25);
    if (!$resp['ok'] || ($resp['status'] ?? 0) >= 400) { ff_debug('Internet Archive advancedsearch failed', ['query' => $query, 'mediaType' => $mediaType, 'status' => (int)($resp['status'] ?? 0), 'error' => (string)($resp['error'] ?? '')]); return ['ok' => false, 'error' => 'Internet Archive unavailable', 'results' => []]; }
    $json = json_decode($resp['body'], true);
    $items = [];
    foreach (($json['response']['docs'] ?? []) as $doc) {
        $identifier = $doc['identifier'] ?? '';
        if ($identifier === '') continue;
        $meta = httpRequest('https://archive.org/metadata/' . rawurlencode($identifier), 'BroadcastUrSelfFileFinder/2.0', 20);
        if (!$meta['ok'] || ($meta['status'] ?? 0) >= 400) continue;
        $metaJson = json_decode($meta['body'], true);
        foreach (($metaJson['files'] ?? []) as $file) {
            $name = $file['name'] ?? '';
            if ($name === '') continue;
            $directUrl = 'https://archive.org/download/' . rawurlencode($identifier) . '/' . str_replace('%2F', '/', rawurlencode($name));
            if (!extensionAllowed($directUrl, $config['allowed_extensions'])) continue;
            $items[] = resultRow(($doc['title'] ?? $identifier) . ' - ' . $name, 'https://archive.org/details/' . rawurlencode($identifier), 'archive.org', 'Internet Archive', $mediaType, $directUrl, 'Download allowed');
        }
    }
    ff_debug('Internet Archive search done', ['query' => $query, 'mediaType' => $mediaType, 'results' => count($items)]);
    return ['ok' => true, 'results' => $items];
}

function searchWikimediaCommons($query, $config) {
    if (empty($config['enable_wikimedia_commons'])) return ['ok' => true, 'results' => []];
    ff_debug('Wikimedia search start', ['query' => $query]);
    $url = 'https://commons.wikimedia.org/w/api.php?action=query&generator=search&gsrsearch=' . rawurlencode($query)
         . '&gsrnamespace=6&gsrlimit=' . (int)$config['max_results'] . '&prop=imageinfo&iiprop=url&format=json';
    $resp = httpRequest($url, 'BroadcastUrSelfFileFinder/2.0', 25);
    if (!$resp['ok'] || ($resp['status'] ?? 0) >= 400) { ff_debug('Wikimedia API failed', ['query' => $query, 'status' => (int)($resp['status'] ?? 0), 'error' => (string)($resp['error'] ?? '')]); return ['ok' => false, 'error' => 'Wikimedia unavailable', 'results' => []]; }
    $json = json_decode($resp['body'], true);
    $items = [];
    foreach (($json['query']['pages'] ?? []) as $page) {
        $img = $page['imageinfo'][0]['url'] ?? '';
        if ($img === '') continue;
        $pageUrl = 'https://commons.wikimedia.org/wiki/' . rawurlencode(str_replace(' ', '_', (string)($page['title'] ?? '')));
        $items[] = resultRow($page['title'] ?? 'Commons image', $pageUrl, 'wikimedia.org', 'Wikimedia Commons', 'image', $img, 'Download allowed', $img);
    }
    ff_debug('Wikimedia search done', ['query' => $query, 'results' => count($items)]);
    return ['ok' => true, 'results' => $items];
}

function searchFreesound($query, $config) {
    if (empty($config['enable_freesound'])) return ['ok' => true, 'results' => []];
    ff_debug('Freesound search start', ['query' => $query, 'api_key' => !empty($config['freesound_api_key'])]);
    $key = trim((string)($config['freesound_api_key'] ?? ''));
    if ($key !== '') {
        $url = 'https://freesound.org/apiv2/search/text/?query=' . rawurlencode($query) . '&page_size=' . (int)$config['max_results'];
        $resp = httpRequest($url, 'BroadcastUrSelfFileFinder/2.0', 25, ['Authorization: Token ' . $key, 'Accept: application/json']);
        if ($resp['ok'] && ($resp['status'] ?? 0) < 400) {
            $json = json_decode($resp['body'], true);
            $items = [];
            foreach (($json['results'] ?? []) as $row) {
                $preview = $row['previews']['preview-hq-mp3'] ?? ($row['previews']['preview-lq-mp3'] ?? '');
                $pageUrl = !empty($row['id']) ? 'https://freesound.org/people/' . rawurlencode((string)($row['username'] ?? '')) . '/sounds/' . rawurlencode((string)$row['id']) . '/' : 'https://freesound.org/';
                if ($preview !== '') {
                    $items[] = resultRow($row['name'] ?? 'Sound', $pageUrl, 'freesound.org', implode(', ', $row['tags'] ?? []), 'audio', $preview, 'Preview download allowed');
                }
            }
            ff_debug('Freesound API search done', ['query' => $query, 'results' => count($items)]);
            return ['ok' => true, 'results' => $items];
        }
    }
    ff_debug('Freesound API key not configured or API failed; using search page fallback', ['query' => $query]);
    $searchPage = 'https://freesound.org/search/?q=' . rawurlencode($query);
    return ['ok' => true, 'results' => [resultRow('Freesound search results for “' . $query . '”', $searchPage, 'freesound.org', 'Open Freesound search page. Add an API key to fetch playable preview results here.', 'audio', '', 'Open source page')]];
}

function formatSecondsHuman($seconds) {
    $seconds = (int)$seconds;
    if ($seconds <= 0) return '';
    $hours = intdiv($seconds, 3600);
    $minutes = intdiv($seconds % 3600, 60);
    $secs = $seconds % 60;
    return $hours > 0
        ? sprintf('%d:%02d:%02d', $hours, $minutes, $secs)
        : sprintf('%d:%02d', $minutes, $secs);
}

function scoreYoutubeResult($query, array $item) {
    $score = 0;
    $haystack = mb_strtolower(trim(($item['title'] ?? '') . ' ' . ($item['author'] ?? '')), 'UTF-8');
    $needles = preg_split('/\s+/', mb_strtolower($query, 'UTF-8')) ?: [];
    foreach ($needles as $needle) {
        $needle = trim($needle);
        if ($needle === '' || mb_strlen($needle, 'UTF-8') < 2) continue;
        if (mb_strpos($haystack, $needle, 0, 'UTF-8') !== false) $score += 8;
    }
    if (stripos($haystack, $query) !== false) $score += 40;
    foreach (['official', 'audio', 'video', 'topic', 'records', 'music'] as $boost) {
        if (mb_strpos($haystack, $boost, 0, 'UTF-8') !== false) $score += 3;
    }
    $viewCount = (int)($item['viewCount'] ?? 0);
    if ($viewCount > 0) $score += min(20, (int)floor(log10(max(10, $viewCount)) * 3));
    if (!empty($item['isLive'])) $score -= 50;
    if (!empty($item['authorVerified'])) $score += 8;
    return $score;
}



function ffYoutubeExtractRowsFromNode($node, $query, &$items, &$seen, $limit = 6) {
    if (count($items) >= $limit || !is_array($node)) return;
    if (isset($node['videoRenderer']) && is_array($node['videoRenderer'])) {
        $vr = $node['videoRenderer'];
        $videoId = trim((string)($vr['videoId'] ?? ''));
        if ($videoId !== '' && preg_match('/^[A-Za-z0-9_-]{11}$/', $videoId) && !isset($seen[$videoId])) {
            $seen[$videoId] = true;
            $title = '';
            foreach (($vr['title']['runs'] ?? []) as $run) {
                $title .= (string)($run['text'] ?? '');
            }
            if ($title === '') $title = (string)($vr['title']['simpleText'] ?? 'YouTube video match');
            $author = '';
            foreach (($vr['ownerText']['runs'] ?? $vr['longBylineText']['runs'] ?? []) as $run) {
                $author .= (string)($run['text'] ?? '');
            }
            $duration = (string)($vr['lengthText']['simpleText'] ?? '');
            $views = (string)($vr['viewCountText']['simpleText'] ?? '');
            $desc = array_filter([$author, $duration ? ('Duration ' . $duration) : '', $views]);
            $items[] = [
                'score' => scoreYoutubeResult($query, ['title' => $title, 'author' => $author]),
                'row' => resultRow(
                    $title,
                    'https://www.youtube.com/watch?v=' . $videoId,
                    'youtube.com',
                    implode(' • ', $desc) ?: 'Direct YouTube video match. Downloads are disabled here.',
                    'video',
                    '',
                    'Open-only',
                    'https://i.ytimg.com/vi/' . $videoId . '/hqdefault.jpg'
                )
            ];
        }
    }
    foreach ($node as $v) {
        if (count($items) >= $limit) break;
        if (is_array($v)) ffYoutubeExtractRowsFromNode($v, $query, $items, $seen, $limit);
    }
}

function ffYoutubeInnertubeSearch($query, $limit = 6) {
    ff_debug('YouTube innertube search start', ['query' => $query, 'limit' => $limit]);
    $searchUrl = 'https://www.youtube.com/results?search_query=' . rawurlencode($query) . '&sp=EgIQAQ%253D%253D&hl=en';
    $resp = httpRequest($searchUrl, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0 Safari/537.36', 20, [
        'Accept-Language: en-US,en;q=0.9',
        'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    ]);
    if (empty($resp['ok']) || (int)($resp['status'] ?? 0) >= 400) { ff_debug('YouTube search page fetch failed', ['query' => $query, 'status' => (int)($resp['status'] ?? 0), 'error' => (string)($resp['error'] ?? '')]); return []; }
    $html = (string)($resp['body'] ?? '');
    if ($html === '') return [];

    $apiKey = '';
    $clientVersion = '';
    if (preg_match('/"INNERTUBE_API_KEY":"([^"]+)"/', $html, $m)) $apiKey = $m[1];
    if (preg_match('/"INNERTUBE_CLIENT_VERSION":"([^"]+)"/', $html, $m)) $clientVersion = $m[1];
    if ($apiKey === '' || $clientVersion === '') { ff_debug('YouTube innertube config missing', ['query' => $query, 'apiKeyFound' => $apiKey !== '', 'clientVersionFound' => $clientVersion !== '']); return []; }

    $payload = json_encode([
        'context' => [
            'client' => [
                'clientName' => 'WEB',
                'clientVersion' => $clientVersion,
                'hl' => 'en',
                'gl' => 'US',
            ],
        ],
        'query' => $query,
        'params' => 'EgIQAQ%3D%3D',
    ], JSON_UNESCAPED_SLASHES);

    $ch = curl_init('https://www.youtube.com/youtubei/v1/search?key=' . urlencode($apiKey));
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 3,
        CURLOPT_TIMEOUT => 20,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $payload,
        CURLOPT_HTTPHEADER => [
            'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0 Safari/537.36',
            'Accept: application/json',
            'Content-Type: application/json',
            'Origin: https://www.youtube.com',
            'Referer: ' . $searchUrl,
            'X-Youtube-Client-Name: 1',
            'X-Youtube-Client-Version: ' . $clientVersion,
        ],
    ]);
    $body = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if ($body === false || $status >= 400) { ff_debug('YouTube innertube endpoint failed', ['query' => $query, 'status' => (int)$status]); return []; }
    $json = json_decode((string)$body, true);
    if (!is_array($json)) { ff_debug('YouTube innertube returned non-JSON', ['query' => $query]); return []; }

    $items = [];
    $seen = [];
    ffYoutubeExtractRowsFromNode($json, $query, $items, $seen, $limit);
    if (!$items) { ff_debug('YouTube innertube found no videoRenderer items', ['query' => $query]); return []; }
    usort($items, function($a, $b) {
        return ($b['score'] <=> $a['score']) ?: strcmp($a['row']['title'], $b['row']['title']);
    });
    ff_debug('YouTube innertube search done', ['query' => $query, 'results' => count($items)]);
    return array_map(function($entry) { return $entry['row']; }, array_slice($items, 0, $limit));
}

function ffYoutubeHtmlFallback($query, $limit = 6) {
    ff_debug('YouTube HTML fallback start', ['query' => $query, 'limit' => $limit]);
    $searchUrl = 'https://www.youtube.com/results?search_query=' . rawurlencode($query) . '&sp=EgIQAQ%253D%253D';
    $resp = httpRequest($searchUrl, 'Mozilla/5.0 (compatible; BroadcastUrSelfFileFinder/2.1; +https://broadcasturself.com)', 20, [
        'Accept-Language: en-US,en;q=0.9',
        'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    ]);
    if (empty($resp['ok']) || (int)($resp['status'] ?? 0) >= 400) {
        ff_debug('YouTube HTML fallback search page fetch failed', ['query' => $query, 'status' => (int)($resp['status'] ?? 0), 'error' => (string)($resp['error'] ?? '')]);
        return [];
    }
    $html = (string)($resp['body'] ?? '');
    if ($html === '') return [];

    $items = [];
    $seen = [];

    if (preg_match('/var ytInitialData = (\{.*?\});/s', $html, $m) || preg_match('/ytInitialData"\s*:\s*(\{.*?\})\s*[,<]/s', $html, $m)) {
        $json = json_decode($m[1], true);
        if (is_array($json)) {
            $walk = function($node) use (&$walk, &$items, &$seen, $query, $limit) {
                if (count($items) >= $limit) return;
                if (!is_array($node)) return;
                if (isset($node['videoRenderer']) && is_array($node['videoRenderer'])) {
                    $vr = $node['videoRenderer'];
                    $videoId = trim((string)($vr['videoId'] ?? ''));
                    if ($videoId !== '' && preg_match('/^[A-Za-z0-9_-]{11}$/', $videoId) && !isset($seen[$videoId])) {
                        $seen[$videoId] = true;
                        $title = '';
                        foreach (($vr['title']['runs'] ?? []) as $run) {
                            $title .= (string)($run['text'] ?? '');
                        }
                        if ($title === '') {
                            $title = (string)($vr['title']['simpleText'] ?? 'YouTube video match');
                        }
                        $author = '';
                        foreach (($vr['ownerText']['runs'] ?? $vr['longBylineText']['runs'] ?? []) as $run) {
                            $author .= (string)($run['text'] ?? '');
                        }
                        $duration = (string)($vr['lengthText']['simpleText'] ?? '');
                        $views = (string)($vr['viewCountText']['simpleText'] ?? '');
                        $desc = array_filter([$author, $duration ? ('Duration ' . $duration) : '', $views]);
                        $items[] = [
                            'score' => scoreYoutubeResult($query, ['title' => $title, 'author' => $author]),
                            'row' => resultRow(
                                $title,
                                'https://www.youtube.com/watch?v=' . $videoId,
                                'youtube.com',
                                implode(' • ', $desc) ?: 'Direct YouTube video match. Downloads are disabled here.',
                                'video',
                                '',
                                'Open-only',
                                'https://i.ytimg.com/vi/' . $videoId . '/hqdefault.jpg'
                            )
                        ];
                    }
                }
                foreach ($node as $v) {
                    if (count($items) >= $limit) break;
                    if (is_array($v)) $walk($v);
                }
            };
            $walk($json);
        }
    }

    if (!$items && preg_match_all('/"videoId":"([A-Za-z0-9_-]{11})"/s', $html, $matches)) {
        foreach ($matches[1] as $videoId) {
            if (isset($seen[$videoId])) continue;
            $seen[$videoId] = true;
            $title = 'YouTube video match';
            if (preg_match('/"videoId":"' . preg_quote($videoId, '/') . '".*?"title":\{"runs":\[\{"text":"(.*?)"\}/s', $html, $m2)) {
                $title = html_entity_decode(stripslashes($m2[1]), ENT_QUOTES, 'UTF-8');
            }
            $items[] = [
                'score' => scoreYoutubeResult($query, ['title' => $title, 'author' => 'YouTube']),
                'row' => resultRow(
                    $title,
                    'https://www.youtube.com/watch?v=' . $videoId,
                    'youtube.com',
                    'Direct YouTube video match. Downloads are disabled here.',
                    'video',
                    '',
                    'Open-only',
                    'https://i.ytimg.com/vi/' . $videoId . '/hqdefault.jpg'
                )
            ];
            if (count($items) >= $limit) break;
        }
    }

    if (!$items) { ff_debug('YouTube HTML fallback found no watch results', ['query' => $query]); return []; }
    usort($items, function($a, $b) {
        return ($b['score'] <=> $a['score']) ?: strcmp($a['row']['title'], $b['row']['title']);
    });
    ff_debug('YouTube HTML fallback done', ['query' => $query, 'results' => count($items)]);
    return array_map(function($entry) { return $entry['row']; }, array_slice($items, 0, $limit));
}


function ffYoutubeSearchEngineFallback($query, $limit = 6) {
    ff_debug('YouTube search-engine fallback start', ['query' => $query, 'limit' => $limit]);
    $searchQueries = [
        'site:youtube.com/watch ' . $query,
        'site:youtube.com/watch "' . $query . '"',
    ];
    $items = [];
    $seen = [];

    foreach ($searchQueries as $engineQuery) {
        $rssUrl = 'https://www.bing.com/search?format=rss&q=' . rawurlencode($engineQuery);
        $resp = httpRequest($rssUrl, 'Mozilla/5.0 (compatible; BroadcastUrSelfFileFinder/2.2; +https://broadcasturself.com)', 20, [
            'Accept: application/rss+xml,application/xml,text/xml;q=0.9,*/*;q=0.8',
            'Accept-Language: en-US,en;q=0.9',
        ]);
        if (!empty($resp['ok']) && (int)($resp['status'] ?? 0) < 400) {
            $xml = @simplexml_load_string((string)($resp['body'] ?? ''));
            if ($xml && isset($xml->channel->item)) {
                foreach ($xml->channel->item as $entry) {
                    $url = trim((string)($entry->link ?? ''));
                    $title = trim(html_entity_decode((string)($entry->title ?? 'YouTube video match'), ENT_QUOTES, 'UTF-8'));
                    if ($url === '') continue;
                    if (preg_match('~(?:youtube\.com/watch\?v=|youtu\.be/)([A-Za-z0-9_-]{11})~', $url, $m)) {
                        $videoId = $m[1];
                        if (isset($seen[$videoId])) continue;
                        $seen[$videoId] = true;
                        $items[] = [
                            'score' => scoreYoutubeResult($query, ['title' => $title, 'author' => 'YouTube']),
                            'row' => resultRow(
                                $title,
                                'https://www.youtube.com/watch?v=' . $videoId,
                                'youtube.com',
                                'Matched from web search. Opens the direct YouTube video page.',
                                'video',
                                '',
                                'Open-only',
                                'https://i.ytimg.com/vi/' . $videoId . '/hqdefault.jpg'
                            )
                        ];
                        if (count($items) >= $limit) break 2;
                    }
                }
            }
        }
    }

    if (!$items) {
        foreach ($searchQueries as $engineQuery) {
            $htmlUrl = 'https://html.duckduckgo.com/html/?q=' . rawurlencode($engineQuery);
            $resp = httpRequest($htmlUrl, 'Mozilla/5.0 (compatible; BroadcastUrSelfFileFinder/2.2; +https://broadcasturself.com)', 20, [
                'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'Accept-Language: en-US,en;q=0.9',
            ]);
            if (empty($resp['ok']) || (int)($resp['status'] ?? 0) >= 400) continue;
            $html = (string)($resp['body'] ?? '');
            if ($html === '') continue;
            if (preg_match_all('~<a[^>]+class="[^"]*result__a[^"]*"[^>]+href="([^"]+)"[^>]*>(.*?)</a>~is', $html, $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    $href = html_entity_decode($match[1], ENT_QUOTES, 'UTF-8');
                    parse_str((string)parse_url($href, PHP_URL_QUERY), $qs);
                    $target = html_entity_decode((string)($qs['uddg'] ?? $href), ENT_QUOTES, 'UTF-8');
                    $title = trim(strip_tags(html_entity_decode($match[2], ENT_QUOTES, 'UTF-8')));
                    if (preg_match('~(?:youtube\.com/watch\?v=|youtu\.be/)([A-Za-z0-9_-]{11})~', $target, $m)) {
                        $videoId = $m[1];
                        if (isset($seen[$videoId])) continue;
                        $seen[$videoId] = true;
                        $items[] = [
                            'score' => scoreYoutubeResult($query, ['title' => $title, 'author' => 'YouTube']),
                            'row' => resultRow(
                                $title ?: 'YouTube video match',
                                'https://www.youtube.com/watch?v=' . $videoId,
                                'youtube.com',
                                'Matched from web search. Opens the direct YouTube video page.',
                                'video',
                                '',
                                'Open-only',
                                'https://i.ytimg.com/vi/' . $videoId . '/hqdefault.jpg'
                            )
                        ];
                        if (count($items) >= $limit) break 2;
                    }
                }
            }
        }
    }

    if (!$items) { ff_debug('YouTube search-engine fallback found no watch results', ['query' => $query]); return []; }
    usort($items, function($a, $b) {
        return ($b['score'] <=> $a['score']) ?: strcmp($a['row']['title'], $b['row']['title']);
    });
    ff_debug('YouTube search-engine fallback done', ['query' => $query, 'results' => count($items)]);
    return array_map(function($entry) { return $entry['row']; }, array_slice($items, 0, $limit));
}

function searchYoutubeOpenOnly($query, $limit = 6) {
    ff_debug('YouTube open-only search start', ['query' => $query, 'limit' => $limit]);
    $results = [];

    // First try YouTube's own internal search endpoint after extracting the current web client config.
    foreach (ffYoutubeInnertubeSearch($query, $limit) as $row) {
        $results[] = ['score' => 100, 'row' => $row];
    }

    // Then try public alternative frontends.
    if (!$results) {
        $instances = [
            'https://yewtu.be/api/v1/search?q=',
            'https://invidious.fdn.fr/api/v1/search?q=',
            'https://inv.nadeko.net/api/v1/search?q=',
            'https://piped.video/api/v1/search?q=',
        ];
        foreach ($instances as $base) {
            ff_debug('Trying alternate YouTube frontend', ['query' => $query, 'base' => $base]);
            $url = $base . rawurlencode($query) . '&type=video&sort_by=relevance';
            $resp = httpRequest($url, 'BroadcastUrSelfFileFinder/2.1', 20, ['Accept: application/json']);
            if (empty($resp['ok']) || (int)($resp['status'] ?? 0) >= 400) {
                continue;
            }
            $json = json_decode((string)($resp['body'] ?? ''), true);
            if (!is_array($json)) continue;
            foreach ($json as $item) {
                if (($item['type'] ?? 'video') !== 'video') continue;
                $videoId = trim((string)($item['videoId'] ?? ''));
                if (!preg_match('/^[A-Za-z0-9_-]{11}$/', $videoId)) continue;
                $title = trim((string)($item['title'] ?? 'YouTube video match'));
                $author = trim((string)($item['author'] ?? 'YouTube'));
                $duration = formatSecondsHuman((int)($item['lengthSeconds'] ?? 0));
                $descriptionBits = array_filter([
                    $author,
                    $duration ? ('Duration ' . $duration) : '',
                    !empty($item['viewCount']) ? (number_format((int)$item['viewCount']) . ' views') : '',
                ]);
                $results[] = [
                    'score' => scoreYoutubeResult($query, $item),
                    'row' => resultRow(
                        $title,
                        'https://www.youtube.com/watch?v=' . $videoId,
                        'youtube.com',
                        implode(' • ', $descriptionBits) ?: 'Direct YouTube video match. Downloads are disabled here.',
                        'video',
                        '',
                        'Open-only',
                        'https://i.ytimg.com/vi/' . $videoId . '/hqdefault.jpg'
                    )
                ];
            }
            if ($results) break;
        }
    }

    if (!$results) {
        foreach (ffYoutubeHtmlFallback($query, $limit) as $row) {
            $results[] = ['score' => 0, 'row' => $row];
        }
    }

    if (!$results) {
        foreach (ffYoutubeSearchEngineFallback($query, max($limit, 10)) as $row) {
            $results[] = ['score' => 0, 'row' => $row];
        }
    }

    if ($results) {
        usort($results, function($a, $b) {
            return ($b['score'] <=> $a['score']) ?: strcmp($a['row']['title'], $b['row']['title']);
        });
        $deduped = [];
        $seen = [];
        foreach ($results as $entry) {
            $videoUrl = $entry['row']['url'] ?? '';
            if ($videoUrl === '' || isset($seen[$videoUrl])) continue;
            $seen[$videoUrl] = true;
            $deduped[] = $entry['row'];
            if (count($deduped) >= $limit) break;
        }
        if ($deduped) {
            ff_debug('YouTube open-only search done', ['query' => $query, 'results' => count($deduped)]);
            return ['ok' => true, 'results' => $deduped];
        }
    }

    ff_debug('YouTube open-only search failed to resolve direct watch URLs', ['query' => $query]);
    return ['ok' => true, 'results' => [
        resultRow('No direct YouTube video match found for “' . $query . '”', '', 'youtube.com', 'The server could not resolve a direct watch URL right now. Try a more exact title or artist name.', 'video', '', 'Unavailable')
    ]];
}

function searchByMode($query, $mode, $config) {
    $results = [];
    $errors = [];

    if ($mode === 'image') {
        foreach ([searchWikimediaCommons($query, $config), searchInternetArchive($query, 'image', $config)] as $res) {
            if (!empty($res['results'])) $results = array_merge($results, $res['results']);
            if (empty($res['ok']) && !empty($res['error'])) $errors[] = $res['error'];
        }
    } elseif ($mode === 'video') {
        foreach ([searchInternetArchive($query, 'video', $config)] as $res) {
            if (!empty($res['results'])) $results = array_merge($results, $res['results']);
            if (empty($res['ok']) && !empty($res['error'])) $errors[] = $res['error'];
        }
        if (!empty($config['allow_youtube_search'])) {
            $yt = searchYoutubeOpenOnly($query);
            $results = array_merge($results, $yt['results']);
        }
    } elseif ($mode === 'audio') {
        foreach ([searchInternetArchive($query, 'audio', $config), searchFreesound($query, $config)] as $res) {
            if (!empty($res['results'])) $results = array_merge($results, $res['results']);
            if (empty($res['ok']) && !empty($res['error'])) $errors[] = $res['error'];
        }
        if (!empty($config['allow_youtube_search'])) {
            $results = array_merge($results, searchYoutubeOpenOnly($query . ' official audio', max(3, (int)ceil(($config['max_results'] ?? 24) / 3)))['results']);
        }
    } else {
        foreach ([searchInternetArchive($query, 'audio', $config), searchInternetArchive($query, 'video', $config), searchWikimediaCommons($query, $config), searchFreesound($query, $config)] as $res) {
            if (!empty($res['results'])) $results = array_merge($results, $res['results']);
            if (empty($res['ok']) && !empty($res['error'])) $errors[] = $res['error'];
        }
        if (!empty($config['allow_youtube_search'])) {
            $results = array_merge($results, searchYoutubeOpenOnly($query)['results']);
        }
    }

    return ['ok' => true, 'results' => dedupeResults($results), 'errors' => $errors];
}

function inspectUrlForDownload($url, $config) {
    $url = normalizeUrl($url);
    if (!$url) return ['ok' => false, 'message' => 'Invalid URL'];
    if (!hostAllowed($url, $config['allowed_domains'])) return ['ok' => false, 'message' => 'Source page only'];
    if (!extensionAllowed($url, $config['allowed_extensions'])) return ['ok' => false, 'message' => 'Not a direct file'];
    $head = httpRequest($url, 'BroadcastUrSelfFileFinder/2.0', 25, [], 'HEAD');
    if (!$head['ok']) return ['ok' => false, 'message' => 'Head request failed'];
    $finalUrl = normalizeUrl($head['final_url'] ?? $url);
    if (!$finalUrl) return ['ok' => false, 'message' => 'Redirect invalid'];
    if (!hostAllowed($finalUrl, $config['allowed_domains'])) return ['ok' => false, 'message' => 'Redirect blocked'];
    if (!extensionAllowed($finalUrl, $config['allowed_extensions'])) return ['ok' => false, 'message' => 'Redirect not a file'];
    $contentLength = parseHeaderValue($head['headers_raw'] ?? '', 'Content-Length');
    $sizeBytes = is_numeric($contentLength) ? (int)$contentLength : 0;
    $maxBytes = (int)$config['max_download_size_mb'] * 1024 * 1024;
    if ($sizeBytes > 0 && $sizeBytes > $maxBytes) return ['ok' => false, 'message' => 'Over 3 GB limit'];
    return ['ok' => true, 'message' => 'Ready', 'final_url' => $finalUrl, 'content_type' => $head['content_type'] ?? '', 'size_bytes' => $sizeBytes];
}

function downloadFile($url, $config, $downloadDir) {
    $check = inspectUrlForDownload($url, $config);
    if (!$check['ok']) return ['success' => false, 'message' => $check['message']];
    $finalUrl = $check['final_url'];
    $ch = curl_init($finalUrl);
    $filename = safeFilenameFromUrl($finalUrl);
    $savePath = rtrim($downloadDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename;
    if (file_exists($savePath)) {
        $filename = time() . '_' . $filename;
        $savePath = rtrim($downloadDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename;
    }
    $fp = fopen($savePath, 'wb');
    if (!$fp) return ['success' => false, 'message' => 'Cannot create file'];
    $maxBytes = (int)$config['max_download_size_mb'] * 1024 * 1024;
    $received = 0;
    curl_setopt_array($ch, [
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5,
        CURLOPT_TIMEOUT => 0,
        CURLOPT_CONNECTTIMEOUT => 15,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_USERAGENT => 'BroadcastUrSelfFileFinder/2.0',
        CURLOPT_FILE => $fp,
        CURLOPT_NOPROGRESS => false,
        CURLOPT_PROGRESSFUNCTION => function($resource, $downloadTotal, $downloadedNow) use ($maxBytes, &$received) {
            $received = (int)$downloadedNow;
            return $downloadedNow > $maxBytes ? 1 : 0;
        },
    ]);
    $ok = curl_exec($ch);
    $error = curl_error($ch);
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    fclose($fp);
    if ($ok === false || $status >= 400) {
        @unlink($savePath);
        return ['success' => false, 'message' => $received > $maxBytes ? 'Stopped at 3 GB limit' : ('Download failed' . ($error ? ': ' . $error : ''))];
    }
    return ['success' => true, 'message' => 'Downloaded', 'filename' => $filename, 'size_bytes' => filesize($savePath) ?: 0];
}

$searchResults = [];
$searchErrors = [];
$downloadResults = [];
$flash = '';
$currentQuery = trim((string)($_SESSION['file_finder_query'] ?? ''));
$currentMode = trim((string)($_SESSION['file_finder_mode'] ?? 'web'));

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_settings'])) {
    $config['freesound_api_key'] = trim((string)($_POST['freesound_api_key'] ?? ''));
    $config['allow_youtube_search'] = !empty($_POST['allow_youtube_search']);
    $config['enable_internet_archive'] = !empty($_POST['enable_internet_archive']);
    $config['enable_wikimedia_commons'] = !empty($_POST['enable_wikimedia_commons']);
    $config['enable_freesound'] = !empty($_POST['enable_freesound']);
    $config['debug_mode'] = !empty($_POST['debug_mode']);
    $config['max_results'] = max(5, min(50, (int)($_POST['max_results'] ?? 24)));
    $config['external_tool_label'] = trim((string)($_POST['external_tool_label'] ?? 'Open External Link'));
    if ($config['external_tool_label'] === '') $config['external_tool_label'] = 'Open External Link';
    $config['external_tool_url'] = normalizeUrl((string)($_POST['external_tool_url'] ?? '')) ?: '';
    $config['max_download_size_mb'] = 3072;
    ff_save_settings($settingsFile, $config);
    $flash = 'File Finder settings saved.';
}

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['search_action'])) {
    $currentQuery = trim((string)($_POST['query'] ?? ''));
    $currentMode = trim((string)($_POST['search_mode'] ?? 'web'));
    if ($currentQuery === '') {
        $searchErrors[] = 'Enter a search term.';
    } else {
        $search = searchByMode($currentQuery, $currentMode, $config);
        $searchResults = $search['results'] ?? [];
        $searchErrors = $search['errors'] ?? [];
        foreach ($searchResults as &$row) {
            $row['can_download'] = false;
            $row['inspect_message'] = $row['note'] ?: 'Open source page';
            $row['size_bytes'] = 0;
            $row['content_type'] = '';
            if (!empty($row['download_url'])) {
                $inspect = inspectUrlForDownload($row['download_url'], $config);
                $row['can_download'] = !empty($inspect['ok']);
                $row['inspect_message'] = $inspect['message'] ?? $row['inspect_message'];
                $row['size_bytes'] = (int)($inspect['size_bytes'] ?? 0);
                $row['content_type'] = (string)($inspect['content_type'] ?? '');
            }
        }
        unset($row);
        $_SESSION['file_finder_results'] = $searchResults;
        $_SESSION['file_finder_query'] = $currentQuery;
        $_SESSION['file_finder_mode'] = $currentMode;
        $_SESSION['file_finder_debug'] = ff_get_debug_log();
        $searchDebug = $_SESSION['file_finder_debug'];
    }
}

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['download_action'])) {
    $storedResults = $_SESSION['file_finder_results'] ?? [];
    $selected = $_POST['selected_urls'] ?? [];
    if (!is_array($selected) || !$selected) {
        $downloadResults[] = ['url' => '', 'status' => 'Skipped', 'message' => 'No items selected', 'filename' => ''];
    } else {
        $allowed = [];
        foreach ($storedResults as $row) {
            if (!empty($row['download_url'])) {
                $allowed[$row['download_url']] = true;
            }
        }
        foreach ($selected as $url) {
            $url = trim((string)$url);
            if (!isset($allowed[$url])) {
                $downloadResults[] = ['url' => $url, 'status' => 'Blocked', 'message' => 'Not from current downloadable results', 'filename' => ''];
                continue;
            }
            $dl = downloadFile($url, $config, $downloadDir);
            if (!empty($dl['success'])) {
                logLine($downloadDir . '/download-log.txt', 'Downloaded: ' . $url . ' -> ' . $dl['filename']);
            }
            $downloadResults[] = ['url' => $url, 'status' => !empty($dl['success']) ? 'Downloaded' : 'Failed', 'message' => $dl['message'] ?? '', 'filename' => $dl['filename'] ?? ''];
        }
    }
    $searchResults = $_SESSION['file_finder_results'] ?? [];
}

if (!$searchResults) {
    $searchResults = $_SESSION['file_finder_results'] ?? [];
}

$downloadedFiles = [];
if (is_dir($downloadDir)) {
    foreach (array_reverse(glob($downloadDir . '/*')) ?: [] as $path) {
        if (is_file($path) && basename($path) !== 'download-log.txt') {
            $downloadedFiles[] = [
                'name' => basename($path),
                'size' => filesize($path) ?: 0,
                'mtime' => filemtime($path) ?: 0,
            ];
        }
        if (count($downloadedFiles) >= 15) break;
    }
}

$pageTitle = 'File Finder';
include __DIR__ . '/includes/header.php';
include __DIR__ . '/includes/sidebar.php';
?>
<div class="admin-shell">
    <div class="admin-panel glass-panel">
        <div class="section-title-row">
            <h1>File Finder</h1>
            <div class="top-actions">
                <a class="btn btn-secondary" href="index.php">Back</a>
            </div>
        </div>
        <p class="muted-text">Search free-source content from Internet Archive, Wikimedia Commons, Freesound, and cleaner one-by-one YouTube video matches. Downloads are limited to direct files from allowed sources and capped at 3 GB.</p>
        <?php if ($flash): ?><div class="admin-alert success"><?= esc($flash) ?></div><?php endif; ?>
        <?php if ($searchErrors): ?><div class="admin-alert warning"><?= esc(implode(' | ', $searchErrors)) ?></div><?php endif; ?>
    </div>

    <div class="admin-panel glass-panel">
        <h2>Search</h2>
        <form method="post" class="finder-grid">
            <input type="hidden" name="search_action" value="1">
            <div>
                <label class="admin-label">Search query</label>
                <input class="admin-input" type="text" name="query" value="<?= esc($currentQuery) ?>" placeholder="old time radio, blues guitar loop, vintage poster, train documentary" required>
            </div>
            <div>
                <label class="admin-label">Mode</label>
                <select class="admin-input" name="search_mode">
                    <option value="web" <?= $currentMode === 'web' ? 'selected' : '' ?>>All free sources</option>
                    <option value="image" <?= $currentMode === 'image' ? 'selected' : '' ?>>Images</option>
                    <option value="video" <?= $currentMode === 'video' ? 'selected' : '' ?>>Video</option>
                    <option value="audio" <?= $currentMode === 'audio' ? 'selected' : '' ?>>Audio</option>
                </select>
            </div>
            <div class="finder-actions">
                <button class="btn" type="submit">Search</button>
            </div>
        </form>
    </div>

    <div class="admin-panel glass-panel">
        <h2>Source Settings</h2>
        <form method="post" class="finder-settings">
            <input type="hidden" name="save_settings" value="1">
            <div class="finder-grid">
<div>
                    <label class="admin-label">Freesound API key (optional)</label>
                    <input class="admin-input" type="text" name="freesound_api_key" value="<?= esc($config['freesound_api_key'] ?? '') ?>" placeholder="Optional for Freesound preview results">
                </div>
                <div>
                    <label class="admin-label">Max results</label>
                    <input class="admin-input" type="number" name="max_results" min="5" max="50" value="<?= (int)$config['max_results'] ?>">
                </div>
                <div>
                    <label class="admin-label">Download limit</label>
                    <input class="admin-input" type="text" value="3 GB hard limit" disabled>
                </div>
                <div>
                    <label class="admin-label">Extra result button label</label>
                    <input class="admin-input" type="text" name="external_tool_label" value="<?= esc($config['external_tool_label'] ?? 'Open External Link') ?>" placeholder="Open External Link">
                </div>
                <div>
                    <label class="admin-label">Extra result button URL</label>
                    <input class="admin-input" type="url" name="external_tool_url" value="<?= esc($config['external_tool_url'] ?? '') ?>" placeholder="https://example.com/tool">
                </div>
            </div>
            <div class="toggle-row">
                <label><input type="checkbox" name="enable_internet_archive" <?= !empty($config['enable_internet_archive']) ? 'checked' : '' ?>> Internet Archive</label>
                <label><input type="checkbox" name="enable_wikimedia_commons" <?= !empty($config['enable_wikimedia_commons']) ? 'checked' : '' ?>> Wikimedia Commons</label>
                <label><input type="checkbox" name="enable_freesound" <?= !empty($config['enable_freesound']) ? 'checked' : '' ?>> Freesound</label>
                <label><input type="checkbox" name="allow_youtube_search" <?= !empty($config['allow_youtube_search']) ? 'checked' : '' ?>> Show one-by-one YouTube video matches</label>
                <label><input type="checkbox" name="debug_mode" <?= !empty($config['debug_mode']) ? 'checked' : '' ?>> Debug mode</label>
            </div>
            <div class="finder-actions">
                <button class="btn" type="submit">Save Settings</button>
            </div>
        </form>
    </div>


    <?php if (!empty($config['debug_mode'])): ?>
    <div class="admin-panel glass-panel">
        <h2>Debug Diagnostics</h2>
        <p class="muted-text">Use this to see exactly which source request is failing on your server. Search once, then check the output below.</p>
        <div class="table-wrap">
            <table class="admin-table">
                <tbody>
                    <tr><th>PHP version</th><td><?= esc(PHP_VERSION) ?></td></tr>
                    <tr><th>cURL loaded</th><td><?= extension_loaded('curl') ? 'Yes' : 'No' ?></td></tr>
                    <tr><th>OpenSSL loaded</th><td><?= extension_loaded('openssl') ? 'Yes' : 'No' ?></td></tr>
                    <tr><th>allow_url_fopen</th><td><?= esc((string)ini_get('allow_url_fopen')) ?></td></tr>
                    <tr><th>cURL CA info</th><td><?= esc((string)(ini_get('curl.cainfo') ?: 'Not set')) ?></td></tr>
                    <tr><th>OpenSSL cafile</th><td><?= esc((string)(ini_get('openssl.cafile') ?: 'Not set')) ?></td></tr>
                    <tr><th>OpenSSL capath</th><td><?= esc((string)(ini_get('openssl.capath') ?: 'Not set')) ?></td></tr>
                </tbody>
            </table>
        </div>
        <?php if ($searchDebug): ?>
            <div class="finder-debug-log">
                <?php foreach ($searchDebug as $line): ?>
                    <div class="finder-debug-line"><?= esc($line) ?></div>
                <?php endforeach; ?>
            </div>
        <?php else: ?>
            <p class="muted-text">No debug lines yet. Run a search with Debug mode enabled.</p>
        <?php endif; ?>
    </div>
    <?php endif; ?>

    <?php if ($searchResults): ?>
    <div class="admin-panel glass-panel">
        <h2>Results</h2>
        <form method="post">
            <input type="hidden" name="download_action" value="1">
            <div class="finder-results">
                <?php foreach ($searchResults as $row): ?>
                    <div class="finder-card">
                        <div class="finder-thumb-wrap">
                            <?php if (!empty($row['thumb'])): ?>
                                <img class="finder-thumb" src="<?= esc($row['thumb']) ?>" alt="">
                            <?php else: ?>
                                <div class="finder-thumb finder-thumb-placeholder">No Preview</div>
                            <?php endif; ?>
                        </div>
                        <div class="finder-body">
                            <h3><?= esc($row['title']) ?></h3>
                            <div class="finder-meta">
                                <span><?= esc($row['source']) ?></span>
                                <span><?= esc(strtoupper($row['mode'])) ?></span>
                            </div>
                            <?php if (!empty($row['description'])): ?><p><?= esc($row['description']) ?></p><?php endif; ?>
                            <div class="finder-links">
                                <a class="btn btn-secondary" href="<?= esc($row['url']) ?>" target="_blank" rel="noopener">Open Source</a>
                                <button
                                    class="btn btn-secondary finder-open-modal"
                                    type="button"
                                    data-title="<?= esc($row['title']) ?>"
                                    data-source="<?= esc($row['source']) ?>"
                                    data-mode="<?= esc(strtoupper($row['mode'])) ?>"
                                    data-url="<?= esc($row['url']) ?>"
                                    data-thumb="<?= esc($row['thumb'] ?? '') ?>"
                                    data-description="<?= esc($row['description'] ?? '') ?>"
                                    data-download-url="<?= esc($row['download_url'] ?? '') ?>"
                                    data-download-ready="<?= !empty($row['can_download']) ? '1' : '0' ?>"
                                    data-download-message="<?= esc($row['inspect_message'] ?? '') ?>"
                                    data-external-url="<?= esc($config['external_tool_url'] ?? '') ?>"
                                    data-external-label="<?= esc($config['external_tool_label'] ?? 'Open External Link') ?>"
                                >Quick Actions</button>
                                <button class="btn btn-secondary finder-copy-url" type="button" data-copy-url="<?= esc($row['url']) ?>">Copy URL</button>
                                <?php if (!empty($config['external_tool_url'])): ?>
                                    <a class="btn btn-secondary" href="<?= esc($config['external_tool_url']) ?>" target="_blank" rel="noopener"><?= esc($config['external_tool_label'] ?? 'Open External Link') ?></a>
                                <?php endif; ?>
                                <?php if (!empty($row['can_download']) && !empty($row['download_url'])): ?>
                                    <label class="download-pick"><input type="checkbox" name="selected_urls[]" value="<?= esc($row['download_url']) ?>"> Select download</label>
                                <?php else: ?>
                                    <span class="finder-note"><?= esc($row['inspect_message']) ?></span>
                                <?php endif; ?>
                            </div>
                            <?php if (!empty($row['can_download'])): ?>
                                <div class="finder-note success-text">Ready to download<?= !empty($row['size_bytes']) ? ' • ' . number_format((int)$row['size_bytes'] / 1048576, 1) . ' MB' : '' ?></div>
                            <?php endif; ?>
                        </div>
                    </div>
                <?php endforeach; ?>
            </div>
            <div class="finder-actions">
                <button class="btn" type="submit">Download Selected</button>
            </div>
        </form>
    </div>
    <?php endif; ?>

    <?php if ($downloadResults): ?>
    <div class="admin-panel glass-panel">
        <h2>Download Results</h2>
        <div class="table-wrap">
            <table class="admin-table">
                <thead><tr><th>URL</th><th>Status</th><th>Message</th><th>Saved File</th></tr></thead>
                <tbody>
                <?php foreach ($downloadResults as $row): ?>
                    <tr>
                        <td><?= $row['url'] ? '<a href="' . esc($row['url']) . '" target="_blank" rel="noopener">' . esc($row['url']) . '</a>' : '-' ?></td>
                        <td><?= esc($row['status']) ?></td>
                        <td><?= esc($row['message']) ?></td>
                        <td><?= esc($row['filename'] ?: '-') ?></td>
                    </tr>
                <?php endforeach; ?>
                </tbody>
            </table>
        </div>
    </div>
    <?php endif; ?>

    <div class="admin-panel glass-panel">
        <h2>Recent Downloads</h2>
        <?php if (!$downloadedFiles): ?>
            <p class="muted-text">No downloads saved yet.</p>
        <?php else: ?>
            <div class="table-wrap">
                <table class="admin-table">
                    <thead><tr><th>File</th><th>Size</th><th>Saved</th><th>Open</th></tr></thead>
                    <tbody>
                    <?php foreach ($downloadedFiles as $file): ?>
                        <tr>
                            <td><?= esc($file['name']) ?></td>
                            <td><?= number_format($file['size'] / 1048576, 2) ?> MB</td>
                            <td><?= date('Y-m-d H:i', (int)$file['mtime']) ?></td>
                            <td><a class="btn btn-secondary btn-small" href="<?= esc($downloadUrlBase . '/' . rawurlencode($file['name'])) ?>" target="_blank" rel="noopener">Open</a></td>
                        </tr>
                    <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        <?php endif; ?>
    </div>
</div>

<div class="finder-modal" id="finderModal" hidden>
    <div class="finder-modal-backdrop" data-close-modal="1"></div>
    <div class="finder-modal-card glass-panel" role="dialog" aria-modal="true" aria-labelledby="finderModalTitle">
        <button class="finder-modal-close" type="button" data-close-modal="1" aria-label="Close">×</button>
        <div class="finder-modal-layout">
            <div class="finder-modal-thumb-wrap">
                <img class="finder-modal-thumb" id="finderModalThumb" src="" alt="" hidden>
                <div class="finder-modal-thumb finder-modal-thumb-placeholder" id="finderModalThumbPlaceholder">No Preview</div>
            </div>
            <div class="finder-modal-body">
                <h3 id="finderModalTitle">Quick Actions</h3>
                <div class="finder-meta">
                    <span id="finderModalSource"></span>
                    <span id="finderModalMode"></span>
                </div>
                <p id="finderModalDescription" class="finder-modal-description"></p>
                <label class="admin-label" for="finderModalUrl">Source URL</label>
                <div class="finder-url-row">
                    <input class="admin-input" id="finderModalUrl" type="text" value="" readonly>
                    <button class="btn btn-secondary" type="button" id="finderModalCopyBtn">Copy URL</button>
                </div>
                <div class="finder-links finder-modal-actions">
                    <a class="btn btn-secondary" id="finderModalOpenBtn" href="#" target="_blank" rel="noopener">Open Source</a>
                    <a class="btn btn-secondary" id="finderModalExternalBtn" href="#" target="_blank" rel="noopener" hidden>Open External Link</a>
                </div>
                <div class="finder-modal-download-wrap">
                    <div class="finder-note" id="finderModalDownloadMessage"></div>
                    <a class="btn" id="finderModalDownloadBtn" href="#" target="_blank" rel="noopener" hidden>Open Direct File</a>
                </div>
            </div>
        </div>
    </div>
</div>
<style>
.finder-grid{display:grid;grid-template-columns:2fr 1fr auto;gap:14px;align-items:end}.finder-actions{margin-top:14px}.finder-settings .finder-actions{margin-top:18px}.toggle-row{display:flex;flex-wrap:wrap;gap:18px;margin-top:12px;color:#f5ddc4}.toggle-row label{display:flex;align-items:center;gap:8px}.finder-results{display:grid;grid-template-columns:1fr;gap:18px}.finder-card{display:grid;grid-template-columns:130px 1fr;gap:18px;padding:16px;border:1px solid rgba(255,181,79,.45);border-radius:18px;background:rgba(31,8,0,.72);box-shadow:0 0 20px rgba(255,166,0,.15)}.finder-thumb-wrap{display:flex;align-items:flex-start;justify-content:center}.finder-thumb{width:110px;height:145px;object-fit:cover;border-radius:12px;border:2px solid rgba(255,181,79,.5);background:#140700}.finder-thumb-placeholder{display:flex;align-items:center;justify-content:center;color:#c9ae90;font-size:13px;text-align:center;padding:10px}.finder-body h3{margin:0 0 8px;color:#ffe8c2}.finder-meta{display:flex;gap:12px;flex-wrap:wrap;color:#d8b78d;font-size:13px;margin-bottom:8px}.finder-links{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-top:10px}.finder-note{color:#e7cfa6}.success-text{color:#91ffcb}.download-pick{display:inline-flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid rgba(255,181,79,.4);border-radius:12px;background:rgba(255,255,255,.04);color:#fff}.finder-modal{position:fixed;inset:0;z-index:9999;display:flex;align-items:center;justify-content:center;padding:24px}.finder-modal[hidden]{display:none !important}.finder-modal-backdrop{position:absolute;inset:0;background:rgba(5,1,0,.72);backdrop-filter:blur(4px)}.finder-modal-card{position:relative;z-index:1;max-width:860px;width:min(100%,860px);padding:22px;border:1px solid rgba(255,181,79,.45)}.finder-modal-layout{display:grid;grid-template-columns:150px 1fr;gap:20px;align-items:start}.finder-modal-thumb{width:130px;height:170px;object-fit:cover;border-radius:14px;border:2px solid rgba(255,181,79,.5);background:#140700}.finder-modal-thumb-placeholder{display:flex;align-items:center;justify-content:center;color:#c9ae90;font-size:13px;text-align:center;padding:10px}.finder-modal-body h3{margin:0 0 10px;color:#ffe8c2}.finder-modal-description{margin:0 0 14px;color:#f0d9b7}.finder-url-row{display:grid;grid-template-columns:1fr auto;gap:12px;align-items:center}.finder-modal-actions{margin-top:14px}.finder-modal-download-wrap{margin-top:14px;display:flex;align-items:center;gap:12px;flex-wrap:wrap}.finder-modal-close{position:absolute;top:12px;right:14px;border:0;background:transparent;color:#ffe8c2;font-size:32px;line-height:1;cursor:pointer}.finder-copy-flash{font-size:12px;color:#91ffcb}.finder-copy-url.copied,.btn.copied{box-shadow:0 0 0 2px rgba(145,255,203,.5) inset}.finder-debug-log{margin-top:16px;display:grid;gap:8px}.finder-debug-line{padding:10px 12px;border-radius:12px;background:rgba(255,255,255,.05);border:1px solid rgba(255,181,79,.24);color:#f4dcc0;font-family:monospace;font-size:12px;word-break:break-word}.admin-table th{width:220px}
@media (max-width:820px){.finder-grid{grid-template-columns:1fr}.finder-card{grid-template-columns:1fr}.finder-thumb-wrap{justify-content:flex-start}.finder-modal-layout{grid-template-columns:1fr}.finder-url-row{grid-template-columns:1fr}}
</style>
<script>
(function(){
  const modal = document.getElementById('finderModal');
  if (!modal) return;
  const title = document.getElementById('finderModalTitle');
  const source = document.getElementById('finderModalSource');
  const mode = document.getElementById('finderModalMode');
  const desc = document.getElementById('finderModalDescription');
  const urlInput = document.getElementById('finderModalUrl');
  const openBtn = document.getElementById('finderModalOpenBtn');
  const copyBtn = document.getElementById('finderModalCopyBtn');
  const extBtn = document.getElementById('finderModalExternalBtn');
  const dlBtn = document.getElementById('finderModalDownloadBtn');
  const dlMsg = document.getElementById('finderModalDownloadMessage');
  const thumb = document.getElementById('finderModalThumb');
  const thumbPlaceholder = document.getElementById('finderModalThumbPlaceholder');

  function setCopiedState(btn, text){
    const original = btn.dataset.originalText || btn.textContent;
    btn.dataset.originalText = original;
    btn.textContent = text;
    btn.classList.add('copied');
    setTimeout(() => { btn.textContent = original; btn.classList.remove('copied'); }, 1400);
  }

  function copyText(value, btn){
    if (!value) return;
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(value).then(() => setCopiedState(btn, 'Copied'));
    } else {
      urlInput.focus();
      urlInput.select();
      try { document.execCommand('copy'); setCopiedState(btn, 'Copied'); } catch (e) {}
    }
  }

  function openModalFromButton(button){
    const data = button.dataset;
    title.textContent = data.title || 'Quick Actions';
    source.textContent = data.source || '';
    mode.textContent = data.mode || '';
    desc.textContent = data.description || '';
    urlInput.value = data.url || '';
    openBtn.href = data.url || '#';

    if (data.thumb) {
      thumb.src = data.thumb;
      thumb.hidden = false;
      thumbPlaceholder.hidden = true;
    } else {
      thumb.removeAttribute('src');
      thumb.hidden = true;
      thumbPlaceholder.hidden = false;
    }

    if (data.externalUrl) {
      extBtn.hidden = false;
      extBtn.href = data.externalUrl;
      extBtn.textContent = data.externalLabel || 'Open External Link';
    } else {
      extBtn.hidden = true;
      extBtn.href = '#';
    }

    if (data.downloadReady === '1' && data.downloadUrl) {
      dlBtn.hidden = false;
      dlBtn.href = data.downloadUrl;
      dlMsg.textContent = data.downloadMessage || 'Direct file ready.';
    } else {
      dlBtn.hidden = true;
      dlBtn.href = '#';
      dlMsg.textContent = data.downloadMessage || '';
    }

    modal.hidden = false;
    document.body.classList.add('modal-open');
  }

  document.querySelectorAll('.finder-open-modal').forEach(btn => {
    btn.addEventListener('click', () => openModalFromButton(btn));
  });

  document.querySelectorAll('.finder-copy-url').forEach(btn => {
    btn.addEventListener('click', () => copyText(btn.dataset.copyUrl || '', btn));
  });

  copyBtn.addEventListener('click', () => copyText(urlInput.value, copyBtn));

  modal.addEventListener('click', (e) => {
    if (e.target && e.target.dataset && e.target.dataset.closeModal === '1') {
      modal.hidden = true;
      document.body.classList.remove('modal-open');
    }
  });

  document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape' && !modal.hidden) {
      modal.hidden = true;
      document.body.classList.remove('modal-open');
    }
  });
})();
</script>
<?php include __DIR__ . '/includes/footer.php'; ?>
