import express, { response } from "express";
import bodyParser from "body-parser";
import path from "path";
import { compileWebSDK } from "../controllers/compiler";
import {
  getAppConfigsFromFS,
  getWebSDKBundleFromFS,
} from "../controllers/workspace";
import { makeHeadersWithCookie } from "../utils";
import { createReadStream } from "fs";
import { getOpenApp } from "../database/cliconfig";
import FormData from "form-data";
import axios from "axios";
import { sendLog, sendHotReloadRequest } from "../websocket";
import { Request, Response, NextFunction } from "express";
export const jsonParser = bodyParser.json({ limit: "50mb" });
const router = express.Router();

//Middleware to check the open app and inject the available cookie into headers
const checkAppInfo = async (req: Request, res: Response, next: NextFunction) => {
  const customReq = req as CustomRequest;
  const appId = customReq.params.appid;
  try {
    const apptileConfig = await getAppConfigsFromFS(appId);
    const openedApp = await getOpenApp(appId);
    if (!openedApp) {
      res.status(400).send("No app is open");
    }
    if (!openedApp?.apptilecookie) {
      res.status(400).send("Apptile cookie not found in the opened app");
    } else {
      customReq.apptileCookie = openedApp.apptilecookie;
      customReq.APPTILE_BACKEND_URL = apptileConfig?.APPTILE_BACKEND_URL;
      req = Object.assign(req, customReq);
      next();
    }
  } catch (err: any) {
    res.status(400).send(err?.message);
    next(err);
  }
};

export interface CustomRequest extends Request {
  apptileCookie: string;
  APPTILE_BACKEND_URL: string;
}

router.get(`/currentWebSdkBundle`, (req: Request, res: Response) => {
  const currentBundlePath = path.resolve(__dirname, '../dist/web-sdk-bundle.js');
  res.sendFile(currentBundlePath);
});

router.get(
  "/compile",
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const sourceFolder = decodeURIComponent(req.query.sourceFolder as string);
      if (!sourceFolder) {
        res.status(400).send("sourceFolder is required");
      }
      const compiled = await compileWebSDK(sourceFolder);
      sendHotReloadRequest();
      res.status(200).json(compiled);
    } catch (err: any) {
      console.error("Error compiling webSDK", err);
      res.status(400).send(err?.message);
      next(err);
    }
  }
);

router.post(
  "/:appid/live/:artifactId",
  checkAppInfo,
  async (req: Request, res, next) => {
    // Upload websdk bundle
    const customReq = req as CustomRequest;
    let formData = new FormData();
    let headers = {};
    const artifactId = req.params.artifactId;
    headers = makeHeadersWithCookie(
      customReq.apptileCookie,
      formData.getHeaders()
    );

    try {
      let response = await axios
        .post(
          `${customReq.APPTILE_BACKEND_URL}/api/web-sdk/live/${artifactId}`,
          formData,
          headers
        )
        .catch((err) => {
          console.error("Error making latest live", err);
          throw err;
        });

      if (response.status >= 400) {
        try {
          const erroMessage = response.data;
          throw new Error("Failed to make live " + erroMessage);
        } catch (err) {
          console.error("Unprocessable error: ", err);
          throw err;
        }
      }
      sendLog(
        `Bundle ${artifactId} made live successfully: ${JSON.stringify(
          response.data,
          null,
          2
        )}`
      );
      res.status(200).send("Done");
    } catch (error) {
      console.error("Error making latest live", error);
      next(error);
    }
  }
);

//Get available partners
router.get("/:appid/partners", checkAppInfo, async (req, res, next) => {
  const customReq = req as CustomRequest;
  try {
    let formData = new FormData();
    const headers = makeHeadersWithCookie(
      customReq.apptileCookie,
      formData.getHeaders()
    );

    try {
      let response = await axios
        .get(`${customReq.APPTILE_BACKEND_URL}/api/web-sdk/partners`, headers)
        .catch((err) => {
          console.error("Error making latest live", err);
          throw err;
        });

      if (response.status >= 400) {
        try {
          const erroMessage = response.data;
          throw new Error("Failed to fetch " + erroMessage);
        } catch (err) {
          console.error("Unprocessable error: ", err);
          throw err;
        }
      }
      res.status(200).send(response.data);
      sendLog("Partners fetched successfully");
    } catch (error) {
      sendLog(`Error fetching partners ${error}`);
      next(error);
    }
  } catch (err: any) {
    res.status(400).send(err?.message);
    next(err);
  }
});

router.get(
  "/:appid/bundles/:partner",
  checkAppInfo,
  async (req: Request, res, next) => {
    const customReq = req as CustomRequest;
    let formData = new FormData();
    const partner = req.params.partner;
    try {
      if (!partner) {
        res.status(400).send("partner is required");
      }

      const headers = makeHeadersWithCookie(
        customReq.apptileCookie,
        formData.getHeaders()
      );

      try {
        let response = await axios
          .get(
            `${customReq.APPTILE_BACKEND_URL}/api/web-sdk/bundles/${partner}`,
            headers
          )
          .catch((err) => {
            console.error("Error making latest live", err);
            throw err;
          });

        if (response.status >= 400) {
          try {
            const erroMessage = response.data;
            throw new Error("Failed to fetch " + erroMessage);
          } catch (err) {
            console.error("Unprocessable error: ", err);
            throw err;
          }
        }
        res.status(200).send(response.data);
        sendLog("Bundles fetched successfully");
      } catch (error) {
        sendLog(`Error fetching bundles ${error}`);
        next(error);
      }
    } catch (err: any) {
      res.status(400).send(err?.message);
      next(err);
    }
  }
);
router.get(
  "/:appid/live/:partner",
  checkAppInfo,
  async (req: Request, res, next) => {
    const customReq = req as CustomRequest;
    let formData = new FormData();
    const partner = req.params.partner;
    try {
      if (!partner) {
        res.status(400).send("partner is required");
      }

      const headers = makeHeadersWithCookie(
        customReq.apptileCookie,
        formData.getHeaders()
      );

      try {
        let response = await axios
          .get(
            `${customReq.APPTILE_BACKEND_URL}/api/web-sdk/live/${partner}`,
            headers
          )
          .catch((err) => {
            console.error("Error making latest live", err);
            throw err;
          });

        if (response.status >= 400) {
          try {
            const erroMessage = response.data;
            throw new Error("Failed to fetch " + erroMessage);
          } catch (err) {
            console.error("Unprocessable error: ", err);
            throw err;
          }
        }
        res.status(200).send(response.data);
        sendLog("Bundles fetched successfully");
      } catch (error) {
        sendLog(`Error fetching bundles ${error}`);
        next(error);
      }
    } catch (err: any) {
      res.status(400).send(err?.message);
      next(err);
    }
  }
);

router.get("/:appid/upload/:partner", checkAppInfo, async (req: Request, res, next) => {
  const customReq = req as CustomRequest;
  const partner = req.params.partner;
  try {
    const webSDKBundle = await getWebSDKBundleFromFS();
    if (!webSDKBundle) {
      res.render("error", { message: "Failed to get webSDK bundle" });
    } else {
      // Upload websdk bundle
      let formData = new FormData();
      formData.append("file", webSDKBundle);
      formData.append("uploadDestination", "plugins");
      let headers = {};

      headers = makeHeadersWithCookie(
        customReq.apptileCookie,
        formData.getHeaders()
      );

      const response = await axios
        .post(
          `${customReq.APPTILE_BACKEND_URL}/api/web-sdk/upload?partner=${partner}`,
          formData,
          headers
        )
        .catch((err) => {
          console.error("Error uploading webSDK bundle", err);
          throw err;
        });

      if (response.status < 400) {
        res.status(200).send(response.data);
        sendLog(
          `WebSDK bundle uploaded successfully: ${JSON.stringify(
            response.data,
            null,
            2
          )}`
        );
      }

      if (response.status >= 400) {
        try {
          const erroMessage = response.data;
          throw new Error("Failed to upload " + erroMessage);
        } catch (err) {
          console.error("Unprocessable error: ", err);
          throw err;
        }
      }
    }
  } catch (err: any) {
    console.error("in uploadWebBundles", err?.message);
    next(err);
  }
});

export default router;
