import sql from "../sql.mjs";
import lib from "../lib.mjs";

const allowedMimes = [ "audio", "image", "video", "%" ];
const auth = async (req, res, next) => {
  if(!req.session) {
    return res.reply({
      code: 401,
      body: "401 - Unauthorized"
    });
  }
  return next();
};

export default (router, tpl) => {
  router.group(/^\/api\/v2/, group => {

    group.get(/$/, (req, res) => {
      res.end("api lol");
    });
  
    group.get(/\/random(\/user\/.+|\/image|\/video|\/audio)?$/, async (req, res) => {
      const user = req.url.split[3] === "user" ? req.url.split[4] : "%";
      const mime = (allowedMimes.filter(n => req.url.split[3]?.startsWith(n))[0] ? req.url.split[3] : "") + "%";
  
      const rows = await sql("items").orderByRaw("rand()").limit(1).where("mime", "ilike", mime).andWhere("username", "ilike", user);
  
      res
        .writeHead(200, { "Content-Type": "application/json" })
        .end(JSON.stringify(rows.length > 0 ? rows[0] : []), "utf-8");
    });
  
    group.get(/\/p\/([0-9]+)/, async (req, res) => { // legacy
      let eps = 100;
      let id = +req.url.split[3];
  
      const rows = await sql("items").where("id", "<", id).orderBy("id", "desc").limit(eps);
  
      const items = {
        items: rows,
        last: rows[rows.length - 1].id
      };
  
      res.writeHead(200, { "Content-Type": "application/json" });
      res.end(JSON.stringify(items), "utf-8");
    });
  
    group.get(/\/item\/[0-9]+$/, async (req, res) => {
      const id = +req.url.split[3];
  
      const item = await sql("items").where("id", id).limit(1);
      const next = await sql("items").select("id").where("id", ">", id).orderBy("id").limit(1);
      const prev = await sql("items").select("id").where("id", "<", id).orderBy("id", "desc").limit(1);
  
      if(item.length === 0)
        return "nope";
  
      const rows = {
        ...item[0],
        ...{
          next: next[0]?.id ?? null,
          prev: prev[0]?.id ?? null
        }
      };
      res.reply({
        type: "application/json",
        body: JSON.stringify(rows)
      });
    });
  
    group.get(/\/user\/.*(\/\d+)?$/, async (req, res) => {
      const user = req.url.split[3];
      const eps = +req.url.split[4] || 50;
  
      const rows = await sql("items")
        .select("id", "mime", "size", "src", "stamp", "userchannel", "username", "usernetwork")
        .where("username", user)
        .orderBy("stamp", "desc")
        .limit(eps);
        
      res.reply({
        type: "application/json",
        body: JSON.stringify(rows.length > 0 ? rows : [])
      });
    });
  
    // adminzeugs
    group.get(/\/admin\/tags\/add$/, auth, async (req, res) => {
      if(!req.url.qs.postid || !req.url.qs.tag) {
        return res.reply({ body: JSON.stringify({
          success: false,
          msg: "missing postid or tag"
        })});
      }
  
      const postid = +req.url.qs.postid;
      const tag = req.url.qs.tag?.trim();
  
      if(tag.length >= 45) {
        return res.reply({ body: JSON.stringify({
          success: false,
          msg: "tag is too long!"
        })});
      }
  
      try {
        let tagid;
        const tag_exists = await sql("tags").select("id", "tag").where("tag", tag);
        if(tag_exists.length === 0) { // create new tag
          await sql("tags").insert({
            tag: tag
          });
          tagid = (await sql("tags").select("id").where("tag", tag))[0].id;
        }
        else {
          tagid = tag_exists[0].id;
        }
        await sql("tags_assign").insert({
          tag_id: tagid,
          item_id: postid,
          user_id: req.session.id
        });
      } catch(err) {
        return res.reply({ body: JSON.stringify({
          success: false,
          msg: err.message,
          tags: await lib.getTags(postid)
        })});
      }
  
      return res.reply({ body: JSON.stringify({
        success: true,
        postid: postid,
        tag: tag,
        tags: await lib.getTags(postid)
      })});
    });
  
    group.get(/\/admin\/tags\/delete$/, auth, async (req, res) => {
      if(!req.url.qs.postid || !req.url.qs.tagid) {
        return res.reply({ body: JSON.stringify({
          success: false,
          msg: "missing postid or tag"
        })});
      }
  
      const postid = +req.url.qs.postid;
      const tagid = +req.url.qs.tagid;
  
      const tags = await lib.getTags(postid);
  
      const tagcheck = tags.filter(t => t.id === tagid)[0]?.id ?? null;
      if(!tagcheck || !tagid || tagid?.length === 0) {
        return res.reply({ body: JSON.stringify({
          success: false,
          msg: "tag is not assigned",
          tags: await lib.getTags(postid)
        })});
      }
      
      let q = sql("tags_assign").where("tag_id", tagid).andWhere("item_id", postid).del();
      if(req.session.level < 50)
        q = q.andWhere("user_id", req.session.id);
      const reply = !!(await q);

      return res.reply({ body: JSON.stringify({
        success: reply,
        tagid: tagid,
        tags: await lib.getTags(postid)
      })});
    });

    group.get(/\/admin\/tags\/suggest$/, auth, async (req, res) => {
      const reply = {
        success: false,
        suggestions: {}
      };

      const searchString = req.url.qs.q;

      if(searchString?.length <= 1) {
        reply.error = 'too short lol';
        return res.reply({ body: JSON.stringify(reply) });
      }

      try {
        const q = await sql('tags')
          .select('tag', sql.raw('count(tags_assign.tag_id) as tagged'))
          .leftJoin('tags_assign', 'tags_assign.tag_id', 'tags.id')
          .whereRaw("normalized like '%' || slugify(?) || '%'", [ searchString ])
          .groupBy('tags.id')
          .orderBy('tagged', 'desc')
          .limit(15);
        reply.success = true;
        reply.suggestions = q;
      } catch(err) {
        reply.error = err.msg;
      }

      return res.reply({ body: JSON.stringify(reply) });
    });
  
    group.get(/\/admin\/tags\/get\/\d+$/, auth, async (req, res) => {
      return res.reply({ body: JSON.stringify({
        tags: await lib.getTags(+req.url.split[5])
      })});
    });
  
    group.get(/\/admin\/deletepost$/, auth, async (req, res) => {
      if(!req.url.qs.postid) {
        return res.reply({ body: JSON.stringify({
          success: true,
          msg: "no postid"
        })});
      }
      const postid = +req.url.qs.postid;
  
      await sql("items").where("id", postid).del();
      res.reply({ body: JSON.stringify({
        success: true
      })});
    });

    group.get(/\/admin\/togglefav$/, auth, async (req, res) => {
      const postid = +req.url.qs.postid;
      
      let favs = await sql('favorites').select('user_id').where('item_id', postid);

      if(Object.values(favs).filter(u => u.user_id === req.session.id)[0]) {
        // del fav
        await sql('favorites').where('user_id', req.session.id).andWhere('item_id', postid).del();
      }
      else {
        // add fav
        await sql('favorites').insert({
          item_id: postid,
          user_id: req.session.id
        });
      }

      favs = await sql('favorites')
        .select('user.user', 'user_options.avatar')
        .leftJoin('user', 'user.id', 'favorites.user_id')
        .leftJoin('user_options', 'user_options.user_id', 'favorites.user_id')
        .where('favorites.item_id', postid);

      res.reply({ body: JSON.stringify({
        success: true,
        itemid: postid,
        favs: favs
      })});
    });

  });

  return router;
};
