const urlModel = require("../models/urlModel.js");
const validator = require("../validators/validator.js");
const shortid = require("shortid");
const baseUrl = "http://localhost:3000";
const { promisify } = require("util");
const { redisClient } = require("../server");

//Connection setup for redis
const SET_ASYNC = promisify(redisClient.SET).bind(redisClient);
const GET_ASYNC = promisify(redisClient.GET).bind(redisClient);

// Converting long URL to short. --> 1st API
const urlShort = async function (req, res) {
  let longUrl = req.body.longUrl;
  const shortCode = shortid.generate().toLowerCase(); //Generating unique random code for each & every entry

  try {
    longUrl = longUrl.trim();
    const requestBody = req.body;

    if (!validator.isValidRequestBody(requestBody)) {
      return res.status(400).send({
        status: false,
        message: "Invalid request parameters. Please provide URL details",
      });
    }

    if (!validator.isValid(longUrl)) {
      return res
        .status(400)
        .send({ status: false, message: "Please provide Long URL." });
    }

    if (!longUrl.includes("//")) {
      return res
        .status(400)
        .send({ status: false, message: "Invalid longUrl" });
    }
    const urlParts = longUrl.split("//");
    const scheme = urlParts[0];
    const uri = urlParts[1];

    if (!uri.includes(".")) {
      return res
        .status(400)
        .send({ status: false, message: "Invalid longUrl" });
    }

    const uriParts = uri.split(".");
    if (
      !(
        (scheme == "http:" || scheme == "https:") &&
        uriParts[0].trim().length &&
        uriParts[1].trim().length
      )
    ) {
      return res
        .status(400)
        .send({ status: false, message: "Invalid longUrl" });
    }

    if (!/(.com|.org|.co.in|.in|.co|.us)/.test(longUrl)) {
      //Validating top level domain
      return res.status(400).send({
        status: false,
        message: "Invalid longUrl",
      });
    }

    //Checking whether the urlcode is already generated by the same longUrl or not.
    const alreadyCodeGeneratedByLongUrl = await urlModel
      .findOne({ longUrl: longUrl })
      .select({ createdAt: 0, updatedAt: 0, __v: 0 });

    if (alreadyCodeGeneratedByLongUrl) {
      return res.status(200).send({
        status: true,
        message: `Short URL already generated for this longURL.`,
        data: alreadyCodeGeneratedByLongUrl,
      });
    }

    const shortUrl = baseUrl + "/" + shortCode; //concatenating base URL & URL code
    const ShorteningUrlData = await urlModel.create({
      longUrl: longUrl,
      shortUrl: shortUrl,
      urlCode: shortCode,
    });

    //setting in cache -> new entries
    await SET_ASYNC(`${shortCode}`, JSON.stringify(longUrl));
    await SET_ASYNC(`${longUrl}`, JSON.stringify(longUrl)); //setting in cache -> new entries

    return res.status(201).send({
      status: true,
      message: `Successfully Shorten the URL`,
      data: ShorteningUrlData,
    });
  } catch (err) {
    console.log(err.message);
    return res.status(500).send({
      status: false,
      Error: err.message,
    });
  }
};

// Fetching data of URL code and redirecting to its long URL. --> 2nd API
let redirectUrl = async function (req, res) {
  try {
    let shortId = req.params.urlCode;
    let cachedLongUrl = await GET_ASYNC(shortId);
    let parsedUrl = JSON.parse(cachedLongUrl)
    // console.log(parsedUrl)

    //from cache
    if (parsedUrl) {
      return res.redirect(307, parsedUrl);
    } else {
      //From Database
      const originalUrlDetails = await urlModel.findOne({
        urlCode: shortId,
      });
      // console.log(originalUrlDetails)

      if (originalUrlDetails) {
        return res.redirect(307, originalUrlDetails.longUrl);
      } else {
        return res.status(404).send({ status: false, msg: "No URL Found" });
      }
    }
  } catch (error) {
    res.status(500).send({ status: false, Error: error.message });
  }
};
module.exports = {
  urlShort,
  redirectUrl,
};
