//Thanks ibro for the TMDB search!

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

        const keywordGroups = {
            trending: ["!trending", "!hot", "!tr", "!!"],
            topRatedMovie: ["!top-rated-movie", "!topmovie", "!tm", "??"],
            topRatedTV: ["!top-rated-tv", "!toptv", "!tt", "::"],
            popularMovie: ["!popular-movie", "!popmovie", "!pm", ";;"],
            popularTV: ["!popular-tv", "!poptv", "!pt", "++"],
        };

        const skipTitleFilter = Object.values(keywordGroups).flat();

        const shouldFilter = !matchesKeyword(keyword, skipTitleFilter);

        // --- TMDB Section ---
        const encodedKeyword = encodeURIComponent(keyword);
        let baseUrlTemplate = null;

        if (matchesKeyword(keyword, keywordGroups.trending)) {
            baseUrlTemplate = (page) => `https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/trending/all/week?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=${page}`)}&simple=true`;
        } else if (matchesKeyword(keyword, keywordGroups.topRatedMovie)) {
            baseUrlTemplate = (page) => `https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/movie/top_rated?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=${page}`)}&simple=true`;
        } else if (matchesKeyword(keyword, keywordGroups.topRatedTV)) {
            baseUrlTemplate = (page) => `https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/tv/top_rated?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=${page}`)}&simple=true`;
        } else if (matchesKeyword(keyword, keywordGroups.popularMovie)) {
            baseUrlTemplate = (page) => `https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/movie/popular?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=${page}`)}&simple=true`;
        } else if (matchesKeyword(keyword, keywordGroups.popularTV)) {
            baseUrlTemplate = (page) => `https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/tv/popular?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=${page}`)}&simple=true`;
        } else {
            baseUrlTemplate = (page) => `https://post-eosin.vercel.app/api/proxy?url=${encodeURIComponent(`https://api.themoviedb.org/3/search/multi?api_key=9801b6b0548ad57581d111ea690c85c8&query=${encodedKeyword}&include_adult=false&page=${page}`)}&simple=true`;
        }

        let dataResults = [];

        if (baseUrlTemplate) {
            const pagePromises = Array.from({ length: 5 }, (_, i) =>
                soraFetch(baseUrlTemplate(i + 1)).then(r => r.json())
            );
            const pages = await Promise.all(pagePromises);
            dataResults = pages.flatMap(p => p.results || []);
        }

        if (dataResults.length > 0) {
                function slugify(str) {
                    return (str || "")
                        .toLowerCase()
                        .replace(/[^a-z0-9\s-]/g, "")
                        .replace(/\s+/g, "-")
                        .replace(/-+/g, "-");
                }
                transformedResults = transformedResults.concat(
                    dataResults
                        .map(result => {
                            if (result.media_type === "movie" || result.title) {
                                const title = result.title || result.name || result.original_title || result.original_name || "Untitled";
                                const slug = slugify(title);
                                return {
                                    title,
                                    image: result.poster_path ? `https://image.tmdb.org/t/p/w500${result.poster_path}` : "",
                                    href: `movie/${result.id}-${slug}`,
                                };
                            } else if (result.media_type === "tv" || result.name) {
                                const title = result.name || result.title || result.original_name || result.original_title || "Untitled";
                                const slug = slugify(title);
                                return {
                                    title,
                                    image: result.poster_path ? `https://image.tmdb.org/t/p/w500${result.poster_path}` : "",
                                    href: `tv/${result.id}-${slug}`,
                                };
                            }
                        })
                        .filter(Boolean)
                        .filter(result => result.title !== "Overflow")
                        .filter(result => result.title !== "My Marriage Partner Is My Student, a Cocky Troublemaker")
                        .filter(r => !shouldFilter || r.title.toLowerCase().includes(keyword.toLowerCase()))
                );
        }

        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: "" }]);
    }
}

function matchesKeyword(keyword, commands) {
    const lower = keyword.toLowerCase();
    return commands.some(cmd => lower.startsWith(cmd.toLowerCase()));
}

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: `If stream fails try again!`,
                airdate: `If stream fails try again!`
            }];

            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: `If stream fails try again!`,
                airdate: `If stream fails try again!`
            }];

            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 {
        function slugify(str) {
            return (str || "")
                .toLowerCase()
                .replace(/[^a-z0-9\s-]/g, "")
                .replace(/\s+/g, "-")
                .replace(/-+/g, "-");
        }
        if(url.startsWith('movie/')) {
            const match = url.match(/movie\/(\d+)-(.+)/);
            if (!match) throw new Error("Invalid movie URL format");
            const movieId = match[1];
            const titleSlug = match[2];
            const movie = [
                { href: `movie/${movieId}-${titleSlug}`, number: 1, title: "Full Movie" }
            ];
            return JSON.stringify(movie);
        } else if(url.startsWith('tv/')) {
            const match = url.match(/tv\/(\d+)-(.+)/);
            if (!match) throw new Error("Invalid TV URL format");
            const showId = match[1];
            const titleSlug = match[2];
            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}-${titleSlug}`,
                        number: episode.episode_number,
                        title: episode.name || ""
                    }));
                    allEpisodes = allEpisodes.concat(episodes);
                }
            }
            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 extractNextActionIdentifier(watchUrl) {
    const htmlResponse = await soraFetch(watchUrl);
    const htmlText = await htmlResponse.text();

    const layoutMatch = htmlText.match(/<script[^>]*src="([^"]*app\/watch\/movie\/[^"]*layout-[^"]*\.js)"[^>]*><\/script><link rel="preload"/);
    
    if (!layoutMatch || !layoutMatch[1]) {
        throw new Error("error 1");
    }

   const beforeLayoutMatch = htmlText.match(/<script[^>]*src="([^"]*\.js)"[^>]*><\/script><script[^>]*src="[^"]*app\/watch\/(movie|tv)\/[^"]*layout-[^"]*\.js"/);

    if (!beforeLayoutMatch || !beforeLayoutMatch[1]) {
        throw new Error("error 2");
    }

    let targetUrl = beforeLayoutMatch[1];
    if (targetUrl.startsWith('/_next/')) {
        targetUrl = 'https://mapple.uk' + targetUrl;
    } else if (!targetUrl.startsWith('http')) {
        targetUrl = 'https://mapple.uk/' + targetUrl;
    }

    try {
        const response = await soraFetch(targetUrl);
        const text = await response.text();
        
        let actionMatch = text.match(/createServerReference\)\("([a-f0-9]{40,})"[^"]*"getStreamUrl/);
        if (!actionMatch) {
            actionMatch = text.match(/createServerReference\)\("([a-f0-9]{40,})"/);
        }
        if (!actionMatch) {
            actionMatch = text.match(/"([a-f0-9]{40,})"[^"]*"getStreamUrl/);
        }
        
        if (actionMatch && actionMatch[1]) {
            return actionMatch[1];
        }
    } catch (e) {
        throw new Error("error 3: " + e);
    }

    throw new Error("error 4");
}

async function extractStreamUrl(ID) {    
    const actionIdentifier = await extractNextActionIdentifier("https://mapple.uk/watch/movie/1061474-superman");
    
    console.log("Action Identifier: " + actionIdentifier);
    
    const sessionResponse = await soraFetch("https://enc-dec.app/api/enc-mapple");
    const sessionData = await sessionResponse.json();
    console.log("Session Data: " + JSON.stringify(sessionData));
    const sessionID = sessionData.result.sessionId || "N/A";
    
    if (ID.startsWith('/movie/') || ID.startsWith('movie/')) {
        const match = ID.match(/movie\/(\d+)/);
        const tmdbID = match ? match[1] : '';
        console.log("Extracted TMDB ID: " + tmdbID);
        const headers = {
            "Content-Type": "text/plain",
            "next-action": actionIdentifier
        };
        const postData = `[{"mediaId":${tmdbID},"mediaType":"movie","tv_slug":"","source":"mapple","useFallbackVideo":false,"sessionId":"${sessionID}"}]`;
        const response = await fetchv2("https://mapple.uk/watch/"+ ID, headers, "POST", postData);
        const data = await response.text();
        console.log("Stream data: " + data);
        
        const lines = data.split('\n');
        let streamData = null;
        for (const line of lines) {
            if (line.includes('"success":true')) {
                streamData = JSON.parse(line.substring(line.indexOf('{')));
                break;
            }
        }
        
        if (streamData && streamData.data && streamData.data.stream_url) {
                const m3u8Response = await soraFetch(streamData.data.stream_url, {
                    headers: {
                        "referer": "https://mapple.uk/",
                        "origin": "https://mapple.uk"
                    }
                });
                const m3u8Text = await m3u8Response.text();
                console.log("M3U8 Playlist: " + m3u8Text);
                
                const streams = [];
                const lines = m3u8Text.split('\n');
                const resolutionNames = {
                    "3840x2160": "4K",
                    "1920x1080": "1080p",
                    "1280x720": "720p",
                    "640x360": "360p"
                };
                for (let i = 0; i < lines.length; i++) {
                    if (lines[i].startsWith('#EXT-X-STREAM-INF')) {
                        const resolutionMatch = lines[i].match(/RESOLUTION=(\d+x\d+)/);
                        const streamUrl = lines[i + 1];
                        if (resolutionMatch && streamUrl && streamUrl.trim()) {
                            const resolution = resolutionMatch[1];
                            const friendlyName = resolutionNames[resolution] || resolution;
                            streams.push({
                                title: friendlyName,
                                streamUrl: streamUrl.trim(),
                                headers: {
                                    "referer": "https://mapple.uk/",
                                    "origin": "https://mapple.uk"
                                }
                            });
                        }
                    }
                }
                
                let englishSubtitleUrl = "";
                try {
                    const subResponse = await soraFetch(`https://mapple.uk/api/subtitles?id=${tmdbID}&mediaType=movie`);
                    const subData = await subResponse.json();
                    const englishSub = subData.find(sub => sub.language === "en");
                    if (englishSub) {
                        englishSubtitleUrl = englishSub.url;
                    }
                } catch (e) {
                    englishSubtitleUrl = "";
                }
                console.log("English Subtitle URL: " + englishSubtitleUrl);
                console.log("Extracted streams: " + JSON.stringify(streams));
                
                return JSON.stringify({
                    streams: streams.length > 0 ? streams : [
                        {
                            title: "Mapple Server",
                            streamUrl: streamData.data.stream_url,
                            headers: {
                                "referer": "https://mapple.uk/",
                                "origin": "https://mapple.uk"
                            }
                        }
                    ],
                    subtitle: englishSubtitleUrl || ""
                });
        } else {
            throw new Error("Failed to extract stream URL");
        }
    } else if (ID.startsWith('/tv/') || ID.startsWith('tv/')) {
        const match = ID.match(/tv\/(\d+)-(\d+)-(\d+)/);
        if (!match) throw new Error("Invalid TV URL format");
        
        const tmdbID = match[1];
        const seasonNumber = match[2];
        const episodeNumber = match[3];
        
        const headers = {
            "Content-Type": "text/plain",
            "next-action": actionIdentifier
        };
        const postData = `[{"mediaId":${tmdbID},"mediaType":"tv","tv_slug":"${seasonNumber}-${episodeNumber}","source":"mapple","useFallbackVideo":false,"sessionId":"${sessionID}"}]`;
        const response = await fetchv2("https://mapple.uk/watch/"+ ID, headers, "POST", postData);
        const data = await response.text();
        console.log("Stream data: " + data);
        
        const lines = data.split('\n');
        let streamData = null;
        for (const line of lines) {
            if (line.includes('"success":true')) {
                streamData = JSON.parse(line.substring(line.indexOf('{')));
                break;
            }
        }
        
        if (streamData && streamData.data && streamData.data.stream_url) {
                const m3u8Response = await soraFetch(streamData.data.stream_url, {
                    headers: {
                        "referer": "https://mapple.uk/",
                        "origin": "https://mapple.uk"
                    }
                });
                const m3u8Text = await m3u8Response.text();
                console.log("M3U8 Playlist: " + m3u8Text);
                
                const streams = [];
                const lines = m3u8Text.split('\n');
                const resolutionNames = {
                    "3840x2160": "4K",
                    "1920x1080": "1080p",
                    "1280x720": "720p",
                    "640x360": "360p"
                };
                for (let i = 0; i < lines.length; i++) {
                    if (lines[i].startsWith('#EXT-X-STREAM-INF')) {
                        const resolutionMatch = lines[i].match(/RESOLUTION=(\d+x\d+)/);
                        const streamUrl = lines[i + 1];
                        if (resolutionMatch && streamUrl && streamUrl.trim()) {
                            const resolution = resolutionMatch[1];
                            const friendlyName = resolutionNames[resolution] || resolution;
                            streams.push({
                                title: friendlyName,
                                streamUrl: streamUrl.trim(),
                                headers: {
                                    "referer": "https://mapple.uk/",
                                    "origin": "https://mapple.uk"
                                }
                            });
                        }
                    }
                }
                
                let englishSubtitleUrl = "";
                try {
                    const subResponse = await soraFetch(`https://mapple.uk/api/subtitles?id=${tmdbID}&mediaType=tv&season=${seasonNumber}&episode=${episodeNumber}`);
                    const subData = await subResponse.json();
                    const englishSub = subData.find(sub => sub.language === "en");
                    if (englishSub) {
                        englishSubtitleUrl = englishSub.url;
                    }
                } catch (e) {
                    englishSubtitleUrl = "";
                }
                console.log("English Subtitle URL: " + englishSubtitleUrl);
                console.log("Extracted streams: " + JSON.stringify(streams));
                
                return JSON.stringify({
                    streams: streams.length > 0 ? streams : [
                        {
                            title: "Mapple Server",
                            streamUrl: streamData.data.stream_url,
                            headers: {
                                "referer": "https://mapple.uk/",
                                "origin": "https://mapple.uk"
                            }
                        }
                    ],
                    subtitle: englishSubtitleUrl || ""
                });
        } else {
            throw new Error("Failed to extract stream URL");
        }
    }
}

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;
        }
    }
}
