const {
  fetcher,
  core,
  wiki,
  musicInfo,
  modules,
  version,
  initlog,
  init,
} = require("../libpoketube-initsys.js");
const { curly } = require("node-libcurl");

const {
  IsJsonString,
  convert,
  getFirstLine,
  capitalizeFirstLetter,
  turntomins,
  getRandomInt,
  getRandomArbitrary,
} = require("../ptutils/libpt-coreutils.js");

const sha384 = modules.hash;

/**
 * Parses a string to JSON, returns null if parsing fails.
 * @param {string} str - The input string to be parsed as JSON.
 * @returns {Object|null} - The parsed JSON object or null if parsing fails.
 */
function getJson(str) {
  try {
    return JSON.parse(str);
  } catch {
    return null;
  }
}

/**
 * Object representing base64-encoded protobuf values for channel tabs.
 * @typedef {Object} ChannelTabs
 * @property {string} community - Base64-encoded value for the community tab.
 * @property {string} shorts - Base64-encoded value for the shorts tab.
 * @property {string} videos - Base64-encoded value for the videos tab.
 * @property {string} streams - Base64-encoded value for the streams tab.
 */

// see https://developers.google.com/youtube/v3/docs/channels/
const ChannelTabs = {
  community: "Y29tbXVuaXR5",
  shorts: "c2hvcnRz",
  videos: "dmlkZW9z",
  streams: "c3RyZWFtcw==", // or "live"
  channels: "Y2hhbm5lbHM=",
  store: "c3RvcmU=",
  released: "cmVsZWFzZWQ=",
  playlist: "cGxheWxpc3Rz",
};

module.exports = function (app, config, renderTemplate) {
  app.get("/download", async function (req, res) {
    try {
      var v = req.query.v;

      renderTemplate(res, req, "download.ejs", {
        v,
        color: await modules
          .getColors(`https://i.ytimg.com/vi/${v}/maxresdefault.jpg`)
          .then((colors) => colors[0].hex()),
        isMobile: req.useragent.isMobile,
      });
    } catch {
      res.redirect("/");
    }
  });

  app.get("/old/watch", async function (req, res) {
    var v = req.query.v;
    var e = req.query.e;
    if (!v) res.redirect("/");

    res.redirect(`/watch?v=${v}`);
  });

  app.get("/api/getchanneltabs", async function (req, res) {
    res.json(ChannelTabs);
  });

  app.get("/search", async (req, res) => {
    const query = req.query.query;
    const tab = req.query.tab;
    const { fetch } = await import("undici");

    var media_proxy = config.media_proxy;

    if (req.useragent.source.includes("Pardus")) {
      var media_proxy = "https://media-proxy.ashley0143.xyz";
    }
    var uaos = req.useragent.os;
    var IsOldWindows;

    if (uaos == "Windows 7" && req.useragent.browser == "Firefox") {
      IsOldWindows = true;
    } else if (uaos == "Windows 8" && req.useragent.browser == "Firefox") {
      IsOldWindows = true;
    } else {
      IsOldWindows = false;
    }

    const poketube_universe_value = "poketube_smart_search";

    if (query?.includes("youtube.com/watch?v=")) {
      try {
        var videoid = query?.split("v=");

        res.redirect("/watch?v=" + videoid[1]);
      } catch {
        return;
      }
    }

    if (query && query.startsWith("!") && query.length > 2) {
      res.redirect("https://lite.duckduckgo.com/lite/?q=" + query);
    }

    if (!query) {
      return res.redirect("/");
    }

    let continuation = req.query.continuation || "";
    let date = req.query.date || "";
    let type = "video";
    let duration = req.query.duration || "";
    let sort = req.query.sort || "";

    try {
      const headers = {};

      const xmlData = await fetch(
        `https://invid-api.poketube.fun/api/v1/search?q=${encodeURIComponent(
          query
        )}&page=${encodeURIComponent(
          continuation
        )}&date=${date}&type=${type}&duration=${duration}&sort=${sort}&hl=en+gb`
      )
        .then((res) => res.text())
        .then((txt) => getJson(txt));

      renderTemplate(res, req, "search.ejs", {
        invresults: xmlData,
        turntomins,
        date,
        type,
        duration,
        sort,
        IsOldWindows,
        tab,
        continuation,
        media_proxy_url: media_proxy,
        results: "",
        q: query,
        summary: "",
      });
    } catch (error) {
      console.error(`Error while searching for '${query}':`, error);
      res.redirect("/");
    }
  });

  app.get("/im-feeling-lucky", function (req, res) {
    res.send("WIP");
  });

  app.get("/web", async (req, res) => {
    const query = req.query.query;
    const tab = req.query.tab;

    const { fetch } = await import("undici");

    const search = await fetch(
      `https://4get.sudovanilla.com/api/v1/web?s=${query}`
    );
    const web = getJson(await search.text());

    if (req.query.lucky === "true") {
      res.redirect("/im-feeling-lucky?query=" + query);
    }
    var uaos = req.useragent.os;
    var IsOldWindows;

    if (uaos == "Windows 7" && req.useragent.browser == "Firefox") {
      IsOldWindows = true;
    } else if (uaos == "Windows 8" && req.useragent.browser == "Firefox") {
      IsOldWindows = true;
    } else {
      IsOldWindows = false;
    }

    const poketube_universe_value = "poketube_smart_search";

    if (query?.includes("youtube.com/watch?v=")) {
      try {
        var videoid = query?.split("v=");

        res.redirect("/watch?v=" + videoid[1]);
      } catch {
        return;
      }
    }

    if (query && query.startsWith("!") && query.length > 2) {
      res.redirect("https://lite.duckduckgo.com/lite/?q=" + query);
    }

    if (!query) {
      return renderTemplate(res, req, "search-web-main.ejs");
    }

    let continuation = req.query.continuation || "";

    try {
      const results = web.web;

      renderTemplate(res, req, "search-web.ejs", {
        j: "",
        IsOldWindows,
        h: "",
        tab,
        continuation,
        isMobile: req.useragent.isMobile,
        results: results,
        q: query,
        summary: "",
      });
    } catch (error) {
      console.error(`Error while searching for '${query}':`, error);
      res.redirect("/");
    }
  });

  app.get("/channel/", async (req, res) => {
    const { fetch } = await import("undici");
    try {
      var media_proxy = config.media_proxy;

      if (req.useragent.source.includes("Pardus")) {
        var media_proxy = "https://media-proxy.ashley0143.xyz";
      }

      var ID = req.query.id;

      if (ID.endsWith("@youtube.com")) {
        ID = ID.slice(0, -"@youtube.com".length);
      }

      if (ID.endsWith("@poketube.fun")) {
        ID = ID.slice(0, -"@poketube.fun".length);
      }
      const tab = req.query.tab;
      const cache = {};

      try {
        // about
        const bout = await fetch(config.tubeApi + `channel?id=${ID}&tab=about`);
        const h = await bout.text();
        var boutJson = JSON.parse(modules.toJson(h));
      } catch {
        boutJson = " ";
      }

      const continuation = req.query.continuation
        ? `&continuation=${req.query.continuation}`
        : "";
      const continuationl = req.query.continuationl
        ? `&continuation=${req.query.continuationl}`
        : "";
      const continuations = req.query.continuations
        ? `&continuation=${req.query.continuations}`
        : "";
      const sort_by = req.query.sort_by || "newest";

      const getChannelData = async (url) => {
        try {
          return await fetch(url)
            .then((res) => res.text())
            .then((txt) => getJson(txt));
        } catch (error) {
          return null;
        }
      };

      const apiUrl = "https://invid-api.poketube.fun/api/v1/channels/";
      const channelUrl = `${apiUrl}${atob(
        ChannelTabs.videos
      )}/${ID}/?sort_by=${sort_by}${continuation}`;
      const shortsUrl = `${apiUrl}${ID}/${atob(
        ChannelTabs.shorts
      )}?sort_by=${sort_by}${continuations}`;
      const streamUrl = `${apiUrl}${ID}/${atob(
        ChannelTabs.streams
      )}?sort_by=${sort_by}${continuationl}`;
      const communityUrl = `${apiUrl}${atob(
        ChannelTabs.community
      )}/${ID}/?hl=en-US`;
      const PlaylistUrl = `${apiUrl}${atob(
        ChannelTabs.playlist
      )}/${ID}/?hl=en-US`;

      const channelINVUrl = `${apiUrl}${ID}/`;

      var [tj, shorts, playlist, stream, c, cinv] = await Promise.all([
        getChannelData(channelUrl),
        getChannelData(shortsUrl),
        getChannelData(PlaylistUrl),
        getChannelData(streamUrl),
        getChannelData(communityUrl),
        getChannelData(channelINVUrl),
      ]);

      function getThumbnailUrl(video) {
        const maxresDefaultThumbnail = video.videoThumbnails.find(
          (thumbnail) => thumbnail.quality === "maxresdefault"
        );

        if (maxresDefaultThumbnail) {
          return `https://vid.puffyan.us/vi/${video.videoId}/maxresdefault.jpg`;
        } else {
          return `https://vid.puffyan.us/vi/${video.videoId}/hqdefault.jpg`;
        }
      }

      cache[ID] = {
        result: {
          tj,
          shorts,
          stream,
          c,
          cinv,
          boutJson,
        },
        timestamp: Date.now(),
      };

      if (cache[ID] && Date.now() - cache[ID].timestamp < 3600000) {
        var { tj, shorts, stream, c, boutJson } = cache[ID].result;
      }

      const subscribers = boutJson.Channel?.Metadata.Subscribers;
      const about = boutJson?.Channel?.Contents?.ItemSection?.About;
      const description = about?.Description.toString().replace(
        /\n/g,
        " <br> "
      );
      const dnoreplace = about?.Description.toString();

      renderTemplate(res, req, "channel.ejs", {
        ID,
        tab,
        shorts,
        j: boutJson,
        sort: sort_by,
        stream,
        tj,
        c,
        cinv,
        convert,
        turntomins,
        media_proxy_url: media_proxy,
        dnoreplace,
        getThumbnailUrl,
        continuation,
        wiki: "",
        getFirstLine,
        isMobile: req.useragent.isMobile,
        about,
        playlist,
        subs:
          typeof subscribers === "string"
            ? subscribers.replace("subscribers", "")
            : "None",
        desc: dnoreplace === "[object Object]" ? "" : description,
      });
    } catch (error) {
      console.error("Failed to render channel page:", error);
      res.redirect("/");
    }
  });
};