"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.jsonParser = void 0;
const express_1 = __importDefault(require("express"));
const workspace_1 = require("../controllers/workspace");
const projectSetup_1 = require("../controllers/projectSetup");
const body_parser_1 = __importDefault(require("body-parser"));
const cliconfig_1 = require("../database/cliconfig");
const projectSetup_2 = require("../controllers/projectSetup");
const websocket_1 = require("../websocket");
const axios_1 = __importDefault(require("axios"));
const chalk_1 = __importDefault(require("chalk"));
const utils_1 = require("../utils");
const path_1 = __importDefault(require("path"));
const fs_1 = __importStar(require("fs"));
const promises_1 = __importDefault(require("fs/promises"));
// import { getMidUrlIntegrationsValue } from '../controllers/claudeAgent';
exports.jsonParser = body_parser_1.default.json();
const router = express_1.default.Router();
// import workspaceMiddleware from '../middlewares/workspace';
router.delete("/workspaces/:workspaceId/closeApp", exports.jsonParser, (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    const fullPath = req.body.fullPath;
    (0, cliconfig_1.closeAppByLocation)(fullPath);
    res.status(200);
    res.end();
}));
router.post("/operation/opencode/:location", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const location = decodeURIComponent(req.params.location);
        yield (0, workspace_1.openWithCode)(location);
        res.status(200);
        res.end();
    }
    catch (err) {
        console.error("Failed when trying to open location with finder");
        next(err);
    }
}));
router.post("/operation/openfinder/:location", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const location = decodeURIComponent(req.params.location);
        yield (0, workspace_1.openWithFinder)(location);
        res.status(200);
        res.end();
    }
    catch (err) {
        console.error("Failed when trying to open location with finder");
        next(err);
    }
}));
router.get("/workspaces/list", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const response = yield (0, workspace_1.listWorkspaces)();
        res.json(response);
    }
    catch (err) {
        console.error("Failure in GET /workspace");
        next(err);
    }
}));
router.post("/workspaces", (req, res) => __awaiter(void 0, void 0, void 0, function* () {
    // add entry in workspace table to link a filesystem path and name
    // link workspace to apptile-server url
    // clone sdk repository and checkout specified branch
}));
router.post("/workspaces/:workspaceId/cloneApp", exports.jsonParser, (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const workspace = parseInt(req.params.workspaceId);
        // TODO(add types to manifest and appIntegrations)
        const manifest = req.body.manifest;
        const appIntegrations = req.body.appIntegrations;
        const apptileConfig = req.body.apptileConfig;
        if (process.env.NODE_ENV === "development") {
            (0, workspace_1.cloneApp)(workspace, manifest, appIntegrations, apptileConfig);
        }
        else {
            (0, workspace_1.cloneAppEc2)(workspace, manifest, appIntegrations, apptileConfig);
        }
        res.status(200);
        res.end();
    }
    catch (err) {
        console.error("Failed to clone app");
        next(err);
    }
}));
router.get("/workspaces/:workspaceId/app/:appId", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    const workspaceId = req.params.workspaceId;
    const appId = req.params.appId;
    try {
        const appLocation = yield (0, workspace_1.getAppLocation)(parseInt(workspaceId), appId);
        const localBundles = yield (0, workspace_1.getLocalBundles)(appLocation);
        res.json({
            appId,
            appRoot: appLocation,
            codePushBundles: localBundles,
        });
    }
    catch (err) {
        next(err);
    }
}));
router.post("/workspaces/:workspaceId/openApp/:appId", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    // find the folder for appid in the workspace
    const appId = req.params.appId;
    const workspaceId = req.params.workspaceId;
    try {
        const appRoot = yield (0, workspace_1.getAppLocation)(parseInt(workspaceId), appId);
        (0, cliconfig_1.insertOrUpdateOpenapp)(workspaceId, appId, appRoot);
        res.status(201);
        res.end();
    }
    catch (err) {
        console.error("Failed to open app");
        next(err);
    }
}));
router.post("/app/:appId/regenerateAppConfig", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const appId = req.params.appId;
        const existingConfig = yield (0, workspace_1.getAppConfigsFromFS)(appId);
        yield (0, workspace_1.generateApptileConfig)(existingConfig);
        res.status(200);
        res.end();
    }
    catch (error) {
        console.error("Failed to regenerate app config", error);
        res.status(400).json({ error: error.message });
    }
}));
router.post("/app/:appId/npmInstall", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    (0, websocket_1.sendLog)("Starting npm install");
    const appId = req.params.appId;
    try {
        const app = yield (0, cliconfig_1.getOpenApp)(appId);
        if (app) {
            yield (0, projectSetup_2.npmInstall)(app.repoPath);
        }
        else {
            throw new Error("Unable to run npm install for an app that is not open " + appId);
        }
        res.status(201);
        res.end();
    }
    catch (err) {
        console.error("failed to do npm install", err);
        next(err);
    }
}));
router.post("/app/:appId/podInstall", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    (0, websocket_1.sendLog)("Starting pod install");
    const appId = req.params.appId;
    try {
        const app = yield (0, cliconfig_1.getOpenApp)(appId);
        if (app) {
            yield (0, projectSetup_2.podInstall)(app.repoPath);
        }
        else {
            throw new Error("Unable to run npm install for an app that is not open " + appId);
        }
        res.status(201);
        res.end();
    }
    catch (err) {
        console.error("failed to do npm install", err);
        next(err);
    }
}));
router.get("/shoplazza-temp-proxy/*", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    // const query = req.query;
    let config = {
        method: "get",
        maxBodyLength: Infinity,
        url: "https://shoplazza-test-store1.myshoplaza.com/api/collections/9f36baea-e6b3-4f1e-8bb7-18c0b44a3e2a/cps?page=0&limit=8",
        headers: {},
    };
    try {
        const { data } = yield axios_1.default.request(config);
        res.json(data);
    }
    catch (err) {
        next(err);
    }
}));
router.get("/app/:appId/remoteCode", (req, res, next) => {
    const appId = req.params.appId;
    (0, projectSetup_1.getRemoteCode)(appId)
        .then((result) => {
        if (result.err) {
            // Set content type to prevent curl from saving error as zip file
            res.setHeader("Content-Type", "application/json");
            return res.status(404).json({ error: result.err });
        }
        if (result.zipPath) {
            const filename = path_1.default.basename(result.zipPath);
            res.download(result.zipPath, filename, (err) => {
                // Delete the zip file after it has been sent (whether successful or not)
                try {
                    // Make sure zipPath exists and is not undefined
                    if (result.zipPath && fs_1.default.existsSync(result.zipPath)) {
                        fs_1.default.unlinkSync(result.zipPath);
                    }
                }
                catch (e) {
                    console.error(`Failed to delete temporary zip file: ${result.zipPath || "unknown"}`);
                }
                if (err) {
                    // Just continue - don't try to send another response
                    // as headers have already been sent
                }
            });
        }
        else {
            return res.status(500).json({ error: "Failed to create zip file" });
        }
    })
        .catch((err) => {
        console.error("Error in remoteCode download endpoint:", err);
        next(err);
    });
});
router.get("/createLog", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    console.log(chalk_1.default.yellow("LOG: " + req.headers["x-telemetry-log"]));
    res.status(200);
    res.end();
}));
// Proxy routes for Supabase API to handle CORS issues
// OAuth token endpoint
router.post("/supabase-proxy/oauth/token", body_parser_1.default.urlencoded({ extended: true }), (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    console.log("Request body: ", req.body);
    try {
        const response = yield axios_1.default.post("https://api.supabase.com/v1/oauth/token", req.body, {
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
            },
        });
        res.status(response.status).json(response.data);
    }
    catch (error) {
        console.error("Error proxying request to Supabase:", error);
        if (axios_1.default.isAxiosError(error) && error.response) {
            res.status(error.response.status).json(error.response.data);
        }
        else {
            res.status(500).json({ error: "Failed to proxy request to Supabase" });
        }
    }
}));
// Projects list endpoint
router.get("/supabase-proxy/projects", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const response = yield axios_1.default.get("https://api.supabase.com/v1/projects", {
            headers: {
                Authorization: req.headers.authorization,
                "Content-Type": "application/json",
            },
        });
        res.status(response.status).json(response.data);
    }
    catch (error) {
        console.error("Error proxying request to Supabase:", error);
        if (axios_1.default.isAxiosError(error) && error.response) {
            res.status(error.response.status).json(error.response.data);
        }
        else {
            res.status(500).json({ error: "Failed to proxy request to Supabase" });
        }
    }
}));
// Project API keys endpoint
router.get("/supabase-proxy/projects/:projectId/api-keys", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const projectId = req.params.projectId;
        const response = yield axios_1.default.get(`https://api.supabase.com/v1/projects/${projectId}/api-keys`, {
            headers: {
                Authorization: req.headers.authorization,
                "Content-Type": "application/json",
            },
        });
        res.status(response.status).json(response.data);
    }
    catch (error) {
        console.error("Error proxying request to Supabase:", error);
        if (axios_1.default.isAxiosError(error) && error.response) {
            res.status(error.response.status).json(error.response.data);
        }
        else {
            res.status(500).json({ error: "Failed to proxy request to Supabase" });
        }
    }
}));
// Supabase token refresh endpoint
router.post("/supabase-proxy/refresh-token", exports.jsonParser, (req, res) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const appId = req.body.appId;
        if (!appId) {
            res.status(400).json({ error: "App ID is required" });
            return;
        }
        const app = yield (0, cliconfig_1.getOpenApp)(appId);
        if (!app) {
            res.status(404).json({ error: "App not found or not open" });
            return;
        }
        // Get app configuration
        const apptileConfig = yield (0, workspace_1.getAppConfigsFromFS)(appId);
        const header = (0, utils_1.makeHeadersWithCookie)(app.apptilecookie, {});
        // First, get the current credentials
        process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
        const credsResponse = yield fetch(`${apptileConfig.APPTILE_BACKEND_URL}/${(0, utils_1.getMidUrlIntegrationsValue)()}/${appId}/appIntegrations/supabase/credentials`, {
            method: "GET",
            headers: Object.assign({}, header.headers),
        });
        if (!credsResponse.ok) {
            throw new Error(`Failed to fetch credentials: ${credsResponse.statusText}`);
        }
        const credsData = yield credsResponse.json();
        if (!credsData.SUPABASE_REFRESH_TOKEN ||
            !credsData.APPTILE_SUPABASE_CLIENT_ID ||
            !credsData.APPTILE_SUPABASE_CLIENT_SECRET) {
            throw new Error("Missing required credentials for token refresh");
        }
        // Prepare form data for token refresh
        const formData = new URLSearchParams();
        formData.append("grant_type", "refresh_token");
        formData.append("refresh_token", credsData.SUPABASE_REFRESH_TOKEN);
        // Call Supabase OAuth endpoint to refresh the token
        const tokenResponse = yield fetch("https://api.supabase.com/v1/oauth/token", {
            method: "POST",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
                Authorization: `Basic ${Buffer.from(`${credsData.APPTILE_SUPABASE_CLIENT_ID}:${credsData.APPTILE_SUPABASE_CLIENT_SECRET}`).toString("base64")}`,
            },
            body: formData.toString(),
        });
        if (!tokenResponse.ok) {
            throw new Error(`Token refresh failed: ${tokenResponse.statusText}`);
        }
        const tokenData = yield tokenResponse.json();
        // Update the credentials in Apptile backend
        const updatedCreds = {
            APPTILE_SUPABASE_CLIENT_ID: credsData.APPTILE_SUPABASE_CLIENT_ID,
            APPTILE_SUPABASE_CLIENT_SECRET: credsData.APPTILE_SUPABASE_CLIENT_SECRET,
            SUPABASE_ACCESS_TOKEN: tokenData.access_token,
            SUPABASE_PROJECT_REF: credsData.SUPABASE_PROJECT_REF,
            SUPABASE_REFRESH_TOKEN: tokenData.refresh_token,
            SUPABASE_ANON_KEY: credsData.SUPABASE_ANON_KEY,
            ACCESS_TOKEN_EXPIRES_IN: tokenData.expires_in,
        };
        const updateResponse = yield fetch(`${apptileConfig.APPTILE_BACKEND_URL}/${(0, utils_1.getMidUrlIntegrationsValue)()}/${appId}/appIntegrations/supabase/credentials?isPlatformType=true`, {
            method: "POST",
            headers: Object.assign(Object.assign({}, header.headers), { "Content-Type": "application/json" }),
            body: JSON.stringify(updatedCreds),
        });
        if (!updateResponse.ok) {
            throw new Error(`Failed to update credentials: ${updateResponse.statusText}`);
        }
        res.status(200).json({
            message: "Supabase token refreshed successfully",
            expires_in: tokenData.expires_in,
            access_token: tokenData.access_token,
        });
    }
    catch (error) {
        console.error("Failed to refresh Supabase token:", error);
        res
            .status(500)
            .json({ error: error.message || "Failed to refresh Supabase token" });
    }
    // res.status(404);
    // res.end();
}));
router.post("/workspaces/:workspaceId/clone-open", exports.jsonParser, (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const workspace = parseInt(req.params.workspaceId);
        // TODO(add types to manifest and appIntegrations)
        const manifest = req.body.manifest;
        const apptileConfig = req.body.apptileConfig;
        yield (0, workspace_1.createAppFolder)(workspace, manifest, apptileConfig);
        const appRoot = yield (0, workspace_1.getAppLocation)(workspace, manifest.uuid);
        (0, cliconfig_1.insertOrUpdateOpenapp)(String(workspace), manifest.uuid, appRoot);
        res.status(201).json({
            message: "App clone and open successful!",
        });
    }
    catch (err) {
        console.error("Failed to clone app", err);
        res.status(400).json({
            err,
        });
    }
}));
// Api to get the file tree
router.get("/:appId/file-tree/:type/:name", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const app = yield (0, cliconfig_1.getOpenApp)(req.params.appId);
        if (!app) {
            res.status(404).json({
                message: "App not found",
            });
            return;
        }
        const appRoot = app.repoPath;
        if (!req.params.type) {
            res.status(400).json({
                message: "Type is required",
            });
            return;
        }
        if (!req.params.name) {
            res.status(400).json({
                message: "Name is required",
            });
            return;
        }
        if (!["plugins", "navigators"].includes(req.params.type)) {
            res.status(400).json({
                message: "Type must be plugins or navigators",
            });
            return;
        }
        const folderPath = `${appRoot}/remoteCode/${req.params.type}/${req.params.name}/source`;
        try {
            yield promises_1.default.access(folderPath, fs_1.constants.F_OK);
        }
        catch (err) {
            res.status(404).json({
                message: "Folder not found",
            });
            return;
        }
        const fileTree = yield (0, workspace_1.getFileTree)(folderPath);
        res.json(fileTree);
    }
    catch (err) {
        console.error("Failed to get file tree", err);
        res.status(400).json({
            err,
        });
    }
}));
// Api to get the file content
router.get("/:appId/file-content/:type/:name/:path", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const app = yield (0, cliconfig_1.getOpenApp)(req.params.appId);
        if (!app) {
            res.status(404).json({
                message: "App not found",
            });
            return;
        }
        const appRoot = app.repoPath;
        if (!req.params.type) {
            res.status(400).json({
                message: "Type is required",
            });
            return;
        }
        if (!req.params.name) {
            res.status(400).json({
                message: "Name is required",
            });
            return;
        }
        if (!["plugins", "navigators"].includes(req.params.type)) {
            res.status(400).json({
                message: "Type must be plugins or navigators",
            });
            return;
        }
        if (!req.params.path) {
            res.status(400).json({
                message: "Path is required",
            });
            return;
        }
        const filePath = `${appRoot}/remoteCode/${req.params.type}/${req.params.name}/source/${req.params.path}`;
        try {
            yield promises_1.default.access(filePath, fs_1.constants.F_OK);
        }
        catch (err) {
            res.status(404).json({
                message: "File not found",
            });
            return;
        }
        const fileContent = yield promises_1.default.readFile(filePath, "utf-8");
        res.json(fileContent);
    }
    catch (err) {
        console.error("Failed to get file tree", err);
        res.status(400).json({
            err,
        });
    }
}));
// Api to manage source files and folders creation and deletion
router.post("/:appId/manage-source", exports.jsonParser, (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const appId = req.params.appId;
        const app = yield (0, cliconfig_1.getOpenApp)(appId);
        if (!app) {
            res.status(404).json({
                message: "App not found",
            });
            return;
        }
        const appRoot = app.repoPath;
        const { itemType, itemName, relativePath, isFolder, action } = req.body;
        // Basic validation for required fields
        if (!itemType ||
            !itemName ||
            !relativePath ||
            typeof isFolder !== "boolean" ||
            !action) {
            res.status(400).json({
                error: "Missing required parameters: itemType, itemName, relativePath, isFolder, action.",
            });
            return;
        }
        if (typeof isFolder !== "boolean") {
            res.status(400).json({ error: "isFolder must be a boolean." });
            return;
        }
        if (!["plugins", "navigators"].includes(itemType)) {
            res
                .status(400)
                .json({ error: "Invalid itemType. Must be 'plugin' or 'navigator'." });
            return;
        }
        if (!["create", "delete"].includes(action)) {
            res
                .status(400)
                .json({ error: "Invalid action. Must be 'create' or 'delete'." });
            return;
        }
        const result = yield (0, workspace_1.manageSourceFileOrFolder)({
            itemType,
            itemName,
            relativePath,
            isFolder,
            action,
        }, `${appRoot}/remoteCode/${itemType}/${itemName}/source`);
        res.status(200).json(result);
    }
    catch (error) {
        console.error(`Failed to ${req.body.action} ${req.body.isFolder ? "folder" : "file"} '${req.body.relativePath}' in ${req.body.itemType} '${req.body.itemName}'`, error);
        // Send the specific error message from the controller, or a generic one
        res.status(400).json({
            error: error.message ||
                "An unexpected error occurred while managing the source item.",
        });
    }
}));
// Api to update source files
router.post("/:appId/update-source", exports.jsonParser, (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
    try {
        const appId = req.params.appId;
        const openedApp = yield (0, cliconfig_1.getOpenApp)(appId);
        if (!openedApp) {
            res.status(404).json({
                message: "App not found. Please open the app first."
            });
            return;
        }
        const appRoot = openedApp.repoPath;
        const { itemType, itemName, relativePath, content } = req.body;
        if (!itemType || !itemName || !relativePath || !content) {
            res.status(400).json({
                error: "Missing required parameters: itemType, itemName, relativePath, content.",
            });
            return;
        }
        if (!["plugins", "navigators"].includes(itemType)) {
            res.status(400).json({
                error: "Invalid itemType. Must be 'plugins' or 'navigators'.",
            });
            return;
        }
        const sourceFilePath = path_1.default.resolve(appRoot, `remoteCode/${itemType}/${itemName}/source/${relativePath}`);
        yield promises_1.default.writeFile(sourceFilePath, content);
        res.status(200).json({
            message: "Source updated successfully",
        });
    }
    catch (error) {
        console.error("Failed to update source", error);
        res.status(400).json({
            error: error.message ||
                "An unexpected error occurred while updating the source item.",
        });
    }
}));
exports.default = router;
