/*Canopy - The next generation of stoner streaming software
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.*/

//Config
const config = require('../../../config.json');

//Node Imports
const { create: ytdlpMaker } = require('youtube-dl-exec');
//Import ytdlp w/ custom path from config so we can force the newest build of yt-dlp from pip
const ytdlp = ytdlpMaker(config.ytdlpPath);
const url = require("node:url");
const validator = require('validator');

//Local Imports
const media = require('../../app/channel/media/media.js');
const regexUtils = require('../regexUtils.js');
const loggerUtils = require('../loggerUtils.js')

/**
 * Pulls metadata for a single youtube video via YT-DLP
 * @param {String} id - Youtube Video ID
 * @param {String} title - Title to add to the given media object
 * @returns {Media} Media object containing relevant metadata
 */
module.exports.fetchYoutubeMetadata = async function(id, title){
    try{
        //Try to pull media from youtube id
        const media = await fetchVideoMetadata(`https://youtu.be/${id}`, title, 'yt');

        //Return found media
        return media;
    //If something went wrong
    }catch(err){
        //If our IP was banned by youtube
        if(err.message.match("Sign in to confirm you’re not a bot.")){
            //Make our own error with blackjack and hookers
            throw loggerUtils.exceptionSmith("The server's IP address has been banned by youtube. Please contact your server's administrator.", "queue");
        //Otherwise if we don't have a good way to handle it
        }else{
            //toss it back up
            throw err;
        }
    }
}

/**
 * Pulls metadata for a playlist of youtube videos via YT-DLP
 * @param {String} id - Youtube Playlist ID
 * @param {String} title - Title to add to the given media objects
 * @returns {Array} Array of  Media objects containing relevant metadata
 */
module.exports.fetchYoutubePlaylistMetadata = async function(id, title){
    try{
        //Try to pull media from youtube id
        const media = await fetchPlaylistMetadata(`https://youtu.be/playlist?list=${id}`, title, 'yt');

        //Return found media
        return media;
    //If something went wrong
    }catch(err){
        //If our IP was banned by youtube
        if(err.message.match("Sign in to confirm you’re not a bot.")){
            //Make our own error with blackjack and hookers
            throw loggerUtils.exceptionSmith("The server's IP address has been banned by youtube. Please contact your server's administrator.", "queue");
        //Otherwise if we don't have a good way to handle it
        }else{
            //toss it back up
            throw err;
        }
    }
}

/* This requires HLS embeds which, in-turn, require daily motion to add us to their CORS exception list
 * Not gonna happen, so we need to use their API for this, or proxy the video
module.exports.fetchDailymotionMetadata = async function(id, title){
    //Pull media from dailymotion link
    const media = await fetchVideoMetadata(`https://dailymotion.com/video/${id}`, title, 'dm');

    //Return found media;
    return media;
}*/

/**
 * Generic single video YTDLP function meant to be used by service-sepecific fetchers which will then be used to fetch video metadata
 * @param {String} link - Link to video in question
 * @param {String} title - Title to add to the given media objects
 * @param {String} type - Link type to attach to the resulting media object
 * @returns {Array} Array of  Media objects containing relevant metadata
 */
async function fetchVideoMetadata(link, title, type, format = 'ba,bv'){
    //Create media list
    const mediaList = [];    

    //Pull raw metadata from YT-DLP
    const rawMetadata = await ytdlpFetch(link, format);

    //Pull data from rawMetadata, sanatizing title to prevent XSS
    const name = validator.escape(validator.trim(rawMetadata.title));

    //Create new raw link object (should we make a class? Probably over kill for a fucking method-less hashtable)
    const rawLinks = {
        audio: [],
        video: [],
        combo: []
    }

    //for each item
    for(const link of rawMetadata.requested_downloads){
        //if there isn't video included
        if(link.vcodec == 'none'){
            //Add the link under the format within the audio map
            rawLinks.audio.push([link.format_note, link.url]);
        //if there isn't audio included
        }else if(link.acodec == 'none'){
            //Add the link under the format within the video map
            rawLinks.video.push([link.format_note, link.url]);
        //otherwise, it includes audio and video
        }else{
            //Add the link under the format within the combo map
            rawLinks.combo.push([link.format_note, link.url]);
        }
    }

    const id = rawMetadata.id;

    //if we where handed a null title
    if(title == null || title == ''){
        //Create new media object from file info substituting filename for title
        mediaList.push(new media(name, name, link, id, type, Number(rawMetadata.duration), rawLinks));
    }else{
        //Create new media object from file info
        mediaList.push(new media(title, name, link, id, type, Number(rawMetadata.duration), rawLinks));
    }

    //Return list of media
    return mediaList;
}

//YT-DLP takes forever to handle playlists, we'll handle this via piped in the future perhaps
/*async function fetchPlaylistMetadata(link, title, type, format = 'b'){
}*/

//Wrapper function for YT-DLP NPM package with pre-set cli-flags
/**
 * Basic async YT-DLP Fetch wrapper, ensuring config
 * @param {String} link - Link to fetch using YT-DLP
 * @param {String} format - Format string to hand YT-DLP, defaults to 'b'
 * @returns {Object} Metadata dump from YT-DLP
 */
async function ytdlpFetch(link, format = 'ba,ogg'){
    //return promise from ytdlp
    return ytdlp(link, {
        format,
        dumpSingleJson: true,
    });
}