async function searchResults(keyword) {
    const results = [];
    try {
        const response = await fetchv2("https://api.cdnlibs.org/api/anime?fields[]=rate_avg&fields[]=rate&fields[]=releaseDate&q=" + keyword);
        const json = await response.json();

        if (json && Array.isArray(json.data)) {
            for (const item of json.data) {
                const image = item.cover?.default || item.cover?.thumbnail || "";
                results.push({
                    title: item.eng_name || item.name || "Unknown",
                    image: "https://passthrough-worker.simplepostrequest.workers.dev/?simple=" + image + "&referer=https://animelib.org/",
                    href: item.slug_url || item.slug || item.id
                });
            }
        }

        return JSON.stringify(results);
    } catch (err) {
        return JSON.stringify([{
            title: "Error",
            image: "Error",
            href: "Error"
        }]);
    }
}

async function extractDetails(slug) {
    try {
        const response = await fetchv2(
            "https://api.cdnlibs.org/api/anime/" + slug + 
            "?fields[]=background&fields[]=eng_name&fields[]=otherNames&fields[]=summary&fields[]=releaseDate&fields[]=type_id&fields[]=caution&fields[]=views&fields[]=close_view&fields[]=rate_avg&fields[]=rate&fields[]=genres&fields[]=tags&fields[]=teams&fields[]=user&fields[]=franchise&fields[]=authors&fields[]=publisher&fields[]=userRating&fields[]=moderated&fields[]=metadata&fields[]=metadata.count&fields[]=metadata.close_comments&fields[]=anime_status_id&fields[]=time&fields[]=episodes&fields[]=episodes_count&fields[]=episodesSchedule&fields[]=shiki_rate"
        );
        const json = await response.json();
        const data = json.data || {};
        const aliases = Array.isArray(data.otherNames) ? data.otherNames.join(", ") : "";
        return JSON.stringify([{
            description: data.summary || "No summary available",
            airdate: data.releaseDate || "Unknown",
            aliases: aliases
        }]);
    } catch (err) {
        return JSON.stringify([{
            description: "Error",
            airdate: "Error",
            aliases: ""
        }]);
    }
}

async function extractEpisodes(slug) {
    const results = [];
    try {
        const response = await fetchv2("https://api.cdnlibs.org/api/episodes?anime_id=" + slug);
        const json = await response.json();

        if (json && Array.isArray(json.data)) {
            for (const episode of json.data) {
                results.push({
                    href: episode.id ? String(episode.id) : "",
                    number: parseFloat(episode.number) || 0
                });
            }
        }

        return JSON.stringify(results);
    } catch (err) {
        return JSON.stringify([{
            href: "Error",
            number: "Error"
        }]);
    }
}

async function extractStreamUrl(ID) {
    try {
        const response = await fetchv2("https://api.cdnlibs.org/api/episodes/" + ID);
        const json = await response.json();
        
        const data = json.data || {};
        const players = data.players || [];
        
        // const parserPromises = players
        //     .filter(player => player.src && player.team && player.team.name)
        //     .map(async (player) => {
        //         try {
        //             const kodikUrl = "https:" + player.src;
        //             const qualitiesJson = await kodikParser(kodikUrl);
        //             const qualities = JSON.parse(qualitiesJson);
                    
        //             let highestQuality = null;
        //             let highestQualityNum = 0;
                    
        //             for (const quality in qualities) {
        //                 if (qualities[quality].src) {
        //                     const qualityNum = parseInt(quality.replace('p', '')) || 0;
        //                     if (qualityNum > highestQualityNum) {
        //                         highestQualityNum = qualityNum;
        //                         highestQuality = qualities[quality].src;
        //                     }
        //                 }
        //             }
                    
        //             if (highestQuality) {

        //                 if (highestQuality.startsWith('//')) {
        //                     highestQuality = 'https:' + highestQuality;
        //                 }
                        
        //                 return {
        //                     title: player.team.name,
        //                     streamUrl: highestQuality,
        //                     headers: {
        //                         "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
        //                         "Referer": "https://kodik.info/"
        //                     }
        //                 };
        //             }
        //             return null;
        //         } catch (err) {
        //             return null;
        //         }
        //     });

        players.sort((a, b) => {
            const order = { Animelib: 0, Kodik: 1 };
            return (order[a.player] ?? 99) - (order[b.player] ?? 99);
        });

        const parserPromises = players
            .filter(player => player.team && player.team.name)
            .map(async (player) => {
                try {
                    let streamUrl = null;
                    let highestQualityNum = 0;

                    if (player.player === "Animelib" && player.video && player.video.quality) {
                        const qualities = player.video.quality;

                        console.log(qualities);
                        
                        for (const qualityItem of qualities) {
                            if (qualityItem.href && qualityItem.quality > highestQualityNum) {
                                highestQualityNum = qualityItem.quality;
                                streamUrl = qualityItem.href;

                                console.log("Found Animelib quality: " + qualityItem.quality + " URL: " + streamUrl);
                            }
                        }
                        
                        // Animelib URLs are relative, prepend base URL
                        if (streamUrl && !streamUrl.startsWith('http')) {
                            // https://video1.cdnlibs.org/.аs/
                            // https://video2.anilib.me/.аs/
                            // https://video3.anilib.me/.аs/
                            streamUrl = 'https://video1.cdnlibs.org/.%D0%B0s/' + streamUrl;
                        }
                    } else if (player.player === "Kodik" && player.src) {
                        const kodikUrl = "https:" + player.src;
                        const qualitiesJson = await kodikParser(kodikUrl);
                        const qualities = JSON.parse(qualitiesJson);
                        
                        for (const quality in qualities) {
                            if (qualities[quality].src) {
                                const qualityNum = parseInt(quality.replace('p', '')) || 0;
                                if (qualityNum > highestQualityNum) {
                                    highestQualityNum = qualityNum;
                                    streamUrl = qualities[quality].src;
                                }
                            }
                        }
                        
                        if (streamUrl && streamUrl.startsWith('//')) {
                            streamUrl = 'https:' + streamUrl;
                        }
                    }

                    if (streamUrl) {
                        return {
                            title: player.team.name + (highestQualityNum ? ` (${highestQualityNum}p)` : '') + (player.player === "Animelib" ? " (Animelib)" : " (Kodik)"),
                            streamUrl,
                            headers: {
                                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
                                "Referer": player.player === "Kodik" ? "https://kodik.info/" : "https://v3.animelib.org/"
                            }
                        };
                    }
                    
                    return null;
                } catch (err) {
                    return null;
                }
            });
        
        const results = await Promise.all(parserPromises);
        
        const streams = results.filter(stream => stream !== null);
        
        return JSON.stringify({
            streams: streams,
            subtitle: "https://none.com"
        });
    } catch (err) {
        return JSON.stringify({
            streams: [],
            subtitle: "https://none.com"
        });
    }
}

async function kodikParser(url) {
  try {
    const headers = {
      "Referer": "https://v3.animelib.org/",
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
    };
    const response = await fetchv2(url, headers);
    const htmlText = await response.text();

    const urlParamsMatch = htmlText.match(/var\s+urlParams\s*=\s*'([^']+)'/);
    const videoInfoTypeMatch = htmlText.match(/videoInfo\.type\s*=\s*'([^']+)'/);
    const videoInfoHashMatch = htmlText.match(/videoInfo\.hash\s*=\s*'([^']+)'/);
    const videoInfoIdMatch = htmlText.match(/videoInfo\.id\s*=\s*'([^']+)'/);

    const urlParams = urlParamsMatch ? JSON.parse(urlParamsMatch[1]) : {};
    const videoInfo_type = videoInfoTypeMatch ? videoInfoTypeMatch[1] : '';
    const videoInfo_hash = videoInfoHashMatch ? videoInfoHashMatch[1] : '';
    const videoInfo_id = videoInfoIdMatch ? videoInfoIdMatch[1] : '';

    const finalData =
      `d=${urlParams.d}` +
      `&d_sign=${urlParams.d_sign}` +
      `&pd=${urlParams.pd}` +
      `&pd_sign=${urlParams.pd_sign}` +
      `&ref=${urlParams.ref}` +
      `&ref_sign=${urlParams.ref_sign}` +
      `&bad_user=false&cdn_is_working=false` +
      `&type=${videoInfo_type}&hash=${videoInfo_hash}&id=${videoInfo_id}&info=%7B%7D`;


    const headers2 = {
      "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
      "Referer": "https://kodik.info",
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
      "X-Requested-With": "XMLHttpRequest"
    };
    const apiResponse = await fetchv2("https://kodik.info/ftor", headers2, "POST", finalData);
    const apiJson = await apiResponse.json();

    const qualities = {};
    
    if (apiJson?.links) {
      for (const quality in apiJson.links) {
        const qualityData = apiJson.links[quality];
        
        if (qualityData && qualityData[0] && qualityData[0].src) {
          const encodedSrc = qualityData[0].src;
          const decodedUrl = decode(encodedSrc);
          
          qualities[quality] = {
            src: decodedUrl,
            type: qualityData[0].type || 'application/x-mpegURL'
          };
        }
      }
    }

    return JSON.stringify(qualities, null, 2);
  } catch (error) {
    console.log(error);
    return JSON.stringify({ error: "error.org" });
  }
}

function decode(input) {
    const _0x1a = ["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", "=", String.fromCharCode, ">="];
    (function() {})();
    const _map = _0x1a[0];
    let _o = '',
        _b = 0,
        _c = 0;
    const _r = [];
    for (let _i = 0; _i < input.length; _i++) {
        const _ch = input[_i];
        if (/[a-zA-Z]/.test(_ch)) {
            const _cc = _ch.charCodeAt(0);
            const _max = _ch <= 'Z' ? 90 : 122;
            let _sh = _cc + 18;
            _r.push(String.fromCharCode(_sh <= _max ? _sh : _sh - 26));
        } else _r.push(_ch);
    }
    const _rot = _r.join('');
    for (let _j = 0; _j < _rot.length; _j++) {
        const _ch = _rot[_j];
        if (_ch === _0x1a[1]) break;
        const _v = _map.indexOf(_ch);
        if (_v === -1) continue;
        _b = (_b << 6) | _v;
        _c += 6;
        if (_c >= 8) {
            _c -= 8;
            _o += _0x1a[2]((_b >> _c) & 0xFF);
        }
    }
    return _o;
}
