async function searchResults(keyword) {
    try {
        let transformedResults = [];

        const encodedKeyword = encodeURIComponent(keyword);
        const apiUrl = `https://thedatabase-brown.vercel.app/api/search?q=${encodedKeyword}&limit=50`;

        const response = await soraFetch(apiUrl);
        const data = await response.json();

        let dataResults = data.results || [];

        if (dataResults.length > 0) {
            transformedResults = dataResults
                .map(result => {
                    const isMovie = result.url.includes('/movies/');
                    const isTV = result.url.includes('/tvs/');

                    return {
                        title: result.title || "Untitled",
                        image: result.poster_path || "",
                        href: isMovie ? `movie/${result.tmdb_id}` : isTV ? `tv/${result.tmdb_id}/1/1` : "",
                    };
                })
        }

        console.log("Transformed Results: " + JSON.stringify(transformedResults));
        return JSON.stringify(transformedResults);
    } catch (error) {
        console.log("Fetch error in searchResults: " + error);
        return JSON.stringify([{ title: "Error", image: "", href: "" }]);
    }
}

async function extractDetails(url) {
    try {
        if(url.includes('movie')) {
            const match = url.match(/movie\/([^\/]+)/);
            if (!match) throw new Error("Invalid URL format");

            const movieId = match[1];
            const responseText = await soraFetch(`https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/movie/${movieId}?api_key=ad301b7cc82ffe19273e55e4d4206885`)}&simple=true`);
            const data = await responseText.json();

            const transformedResults = [{
                description: data.overview || 'No description available',
                aliases: `Duration: ${data.runtime ? data.runtime + " minutes" : 'Unknown'}`,
                airdate: `Released: ${data.release_date ? data.release_date : 'Unknown'}`
            }];

            return JSON.stringify(transformedResults);
        } else if(url.includes('tv')) {
            const match = url.match(/tv\/([^\/]+)/);
            if (!match) throw new Error("Invalid URL format");

            const showId = match[1];
            const responseText = await soraFetch(`https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/tv/${showId}?api_key=ad301b7cc82ffe19273e55e4d4206885`)}&simple=true`);
            const data = await responseText.json();

            const transformedResults = [{
                description: data.overview || 'No description available',
                aliases: `Duration: ${data.episode_run_time && data.episode_run_time.length ? data.episode_run_time.join(', ') + " minutes" : 'Unknown'}`,
                airdate: `Aired: ${data.first_air_date ? data.first_air_date : 'Unknown'}`
            }];

            console.log(JSON.stringify(transformedResults));
            return JSON.stringify(transformedResults);
        } else {
            throw new Error("Invalid URL format");
        }
    } catch (error) {
        console.log('Details error: ' + error);
        return JSON.stringify([{
            description: 'Error loading description',
            aliases: 'Duration: Unknown',
            airdate: 'Aired/Released: Unknown'
        }]);
    }
}

async function extractEpisodes(url) {
    try {
        if(url.includes('movie')) {
            const match = url.match(/movie\/([^\/]+)/);
            
            if (!match) throw new Error("Invalid URL format");
            
            const movieId = match[1];
            
            const movie = [
                { href: `/movie/${movieId}`, number: 1, title: "Full Movie" }
            ];

            console.log(movie);
            return JSON.stringify(movie);
        } else if(url.includes('tv')) {
            const match = url.match(/tv\/([^\/]+)\/([^\/]+)\/([^\/]+)/);
            
            if (!match) throw new Error("Invalid URL format");
            
            const showId = match[1];
            
            const showResponseText = await soraFetch(`https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/tv/${showId}?api_key=ad301b7cc82ffe19273e55e4d4206885`)}&simple=true`);
            const showData = await showResponseText.json();
            
            let allEpisodes = [];
            for (const season of showData.seasons) {
                const seasonNumber = season.season_number;

                if(seasonNumber === 0) continue;
                
                const seasonResponseText = await soraFetch(`https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/tv/${showId}/season/${seasonNumber}?api_key=ad301b7cc82ffe19273e55e4d4206885`)}&simple=true`);
                const seasonData = await seasonResponseText.json();
                
                if (seasonData.episodes && seasonData.episodes.length) {
                    const episodes = seasonData.episodes.map(episode => ({
                        href: `/tv/${showId}/${seasonNumber}/${episode.episode_number}`,
                        number: episode.episode_number,
                        title: episode.name || ""
                    }));
                    allEpisodes = allEpisodes.concat(episodes);
                }
            }
            
            console.log(allEpisodes);
            return JSON.stringify(allEpisodes);
        } else {
            throw new Error("Invalid URL format");
        }
    } catch (error) {
        console.log('Fetch error in extractEpisodes: ' + error);
        return JSON.stringify([]);
    }    
}

async function extractStreamUrl(ID) {
    const parts = ID.split('/').filter(Boolean);
    const type = parts[0];
    const id = parts[1];
    const season = parts[2];
    const episode = parts[3];
    
    try {
        if (type === 'movie') {
            const response = await soraFetch(`https://thedatabase-brown.vercel.app/api/search?tmdb=${id}`);
            const data = await response.json();
            
            const baseUrl = data.results[0].full_url;
            console.log("Base URL: " + baseUrl);
            
            const htmlResponse = await soraFetch(baseUrl);
            const htmlText = htmlResponse ? await htmlResponse.text() : "";
            
            if (htmlText.includes('Error') && htmlText.includes('1015') && htmlText.includes('rate limited')) {
                return JSON.stringify({
                    streams: [{
                        title: "Rate Limited - Please slow down and try again later",
                        streamUrl: "",
                        headers: {}
                    }],
                    subtitle: "None"
                });
            }
            
            const fileRegex1 = /<tr data-entry="true"[^>]*data-name="([^"]+)"[^>]*data-url="([^"]+)"[\s\S]*?data-sort="(\d+)"/g;
            const fileRegex2 = /data-name="([^"]+)"[^>]*data-url="([^"]+)"[\s\S]*?data-sort="(\d+)"/g;
            
            let matches = Array.from(htmlText.matchAll(fileRegex1));
            console.log("Regex1 matches: " + matches.length);
            
            if (matches.length === 0) {
                matches = Array.from(htmlText.matchAll(fileRegex2));
                console.log("Regex2 matches: " + matches.length);
            }
            
            const streams = [];
            
            for (const match of matches) {
                const filename = match[1];
                const fileUrl = match[2];
                const sizeBytes = parseInt(match[3]);
                const sizeGB = (sizeBytes / 1073741824).toFixed(1);
                
                const fileExt = filename.split('.').pop().toUpperCase();
                const isValidType = fileExt === 'MP4' || fileExt === 'MKV';
                
                console.log(`File: ${filename}, Ext: ${fileExt}, Valid: ${isValidType}`);
                
                if (isValidType) {
                    const cleanName = filename.replace(/\./g, ' ').replace(/\.[^.]+$/, '').trim();
                    
                    streams.push({
                        title: `[${fileExt}] [${sizeGB} GB] ${cleanName}`,
                        streamUrl: encodeURIComponent(`${baseUrl}${filename}`),
                        headers: {},
                        sizeGB: parseFloat(sizeGB)
                    });
                }
            }
            
            streams.sort((a, b) => a.sizeGB - b.sizeGB);
            
            streams.forEach(stream => delete stream.sizeGB);
            
            const result = {
                streams: streams,
                subtitle: "None"
            };
            
            console.log("Extracted streams: " + JSON.stringify(result));
            return JSON.stringify(result);
        } else if (type === 'tv') {
            const response = await soraFetch(`https://thedatabase-brown.vercel.app/api/search?tmdb=${id}`);
            const data = await response.json();

            const baseUrl = data.results[0].full_url;
            const seasonListHtml = await (await soraFetch(baseUrl)).text();
            
            if (seasonListHtml.includes('Error') && seasonListHtml.includes('1015') && seasonListHtml.includes('rate limited')) {
                return JSON.stringify({
                    streams: [{
                        title: "Rate Limited - Please slow down and try again later",
                        streamUrl: "",
                        headers: {}
                    }],
                    subtitle: "None"
                });
            }
            
            if (!seasonListHtml) {
                return JSON.stringify({ streams: [], subtitle: "None" });
            }
            
            const seasonRegex = new RegExp(`data-name="Season\\s+${season}"[^>]*data-url="([^"]+)"`, 'i');
            const seasonMatch = seasonListHtml.match(seasonRegex);
            
            if (!seasonMatch) {
                return JSON.stringify({ streams: [], subtitle: "None" });
            }
            
            const domain = baseUrl.split('/').slice(0, 3).join('/');
            const seasonUrl = `${domain}${seasonMatch[1]}`;
            
            const episodeListHtml = await (await soraFetch(seasonUrl)).text();
            
            if (episodeListHtml.includes('Error') && episodeListHtml.includes('1015') && episodeListHtml.includes('rate limited')) {
                return JSON.stringify({
                    streams: [{
                        title: "Rate Limited - Please slow down and try again later",
                        streamUrl: "",
                        headers: {}
                    }],
                    subtitle: "None"
                });
            }
            
            if (!episodeListHtml) {
                return JSON.stringify({ streams: [], subtitle: "None" });
            }
            
            const episodePadded = String(episode).padStart(2, '0');
            const seasonPadded = String(season).padStart(2, '0');
            const episodePattern = `S${seasonPadded}E${episodePadded}`;
            
            const fileRegex = new RegExp(`data-name="([^"]*${episodePattern}[^"]*)"[^>]*data-url="([^"]+)"[\\s\\S]*?data-sort="(\\d+)"`, 'gi');
            const matches = Array.from(episodeListHtml.matchAll(fileRegex));
            
            const streams = [];
            
            for (const match of matches) {
                const filename = match[1];
                const sizeBytes = parseInt(match[3]);
                const sizeGB = (sizeBytes / 1073741824).toFixed(1);
                
                const fileExt = filename.split('.').pop().toUpperCase();
                
                if (fileExt === 'MP4' || fileExt === 'MKV') {
                    const cleanName = filename.replace(/\./g, ' ').replace(/\.[^.]+$/, '').trim();
                    
                    streams.push({
                        title: `[${fileExt}] [${sizeGB} GB] ${cleanName}`,
                        streamUrl: encodeURIComponent(`${seasonUrl}${filename}`),
                        headers: {},
                        sizeGB: parseFloat(sizeGB)
                    });
                }
            }
            
            streams.sort((a, b) => a.sizeGB - b.sizeGB);
            streams.forEach(stream => delete stream.sizeGB);
            
            return JSON.stringify({
                streams: streams,
                subtitle: "None"
            });
        }
    } catch (error) {
        console.log('Fetch error in extractStreamUrl: ' + error);
        return JSON.stringify({
            streams: [],
            subtitle: "None"
        });
    }
}

async function soraFetch(url, options = { headers: {}, method: 'GET', body: null, encoding: 'utf-8' }) {
    try {
        return await fetchv2(
            url,
            options.headers ?? {},
            options.method ?? 'GET',
            options.body ?? null,
            true,
            options.encoding ?? 'utf-8'
        );
    } catch(e) {
        try {
            return await fetch(url, options);
        } catch(error) {
            return null;
        }
    }
}
