"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 () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __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());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HotCreator = void 0;
const ppath = __importStar(require("path"));
const HotIO_1 = require("./HotIO");
const HotStaq_1 = require("./HotStaq");
/**
 * Creates stuff for the CLI.
 */
class HotCreator {
    constructor(logger, name) {
        this.name = name;
        this.hotstaqVersion = "";
        this.type = "web-api";
        this.language = "ts";
        this.outputDir = ppath.normalize(`${process.cwd()}/${name}/`);
        this.logger = logger;
        this.createCommands = {
            init: "npm install",
            transpileTS: "npm run build",
            generateAPI: "node ./build/cli.js generate --copy-to ./public/js/"
        };
        this.npmCommands = {
            start: "",
            develop: "",
            test: "node ./build/cli.js --dev --env-file .env run --server-type api --api-test && node ./build/cli.js --dev --env-file .env run --server-type web --web-test",
            build: "",
            buildWebAPI: "node ./build/cli.js generate --api --generate-type javascript --copy-to ./public/js/",
            buildWebAPIDebug: "node ./build/cli.js generate --api --generate-type javascript --copy-to ./public/js/",
            buildDoc: "node ./build/cli.js generate --generate-type openapi-3.0.0-yaml",
            buildInterfaces: "node ./build/cli.js build --interfaces --interfaces-out ./src/object-defs/"
        };
    }
    /**
     * Copy the libraries over to a new location.
     */
    copyLibraries(location) {
        return __awaiter(this, void 0, void 0, function* () {
            const buildWebDir = ppath.normalize(`${__dirname}/../../build-web`);
            yield HotIO_1.HotIO.copyFile(`${buildWebDir}/HotStaq.js`, ppath.normalize(`${location}/HotStaq.js`));
            yield HotIO_1.HotIO.copyFile(`${buildWebDir}/HotStaq.min.js`, ppath.normalize(`${location}/HotStaq.min.js`));
        });
    }
    /**
     * Create an app.
     */
    create() {
        return __awaiter(this, void 0, void 0, function* () {
            if ((this.name == null) || (this.name === ""))
                throw new Error("Name cannot be empty.");
            this.logger.info(`Creating "${this.name}" of type ${this.type} for language ${this.language}...`);
            HotStaq_1.HotStaq.checkHotSiteName(this.name, true);
            this.outputDir = ppath.normalize(this.outputDir);
            this.logger.info(`Outputting to directory: ${this.outputDir}`);
            yield HotIO_1.HotIO.mkdir(ppath.join(this.outputDir, "/public/js/"));
            yield HotIO_1.HotIO.mkdir(ppath.join(this.outputDir, "/.vscode/"));
            yield HotIO_1.HotIO.mkdir(ppath.join(this.outputDir, "/src/"));
            let readMeBuildSteps = "";
            if (this.language === "ts") {
                readMeBuildSteps = `
	npm run build

This will transpile the TypeScript into ES6 JavaScript by default. After this is done building, enter: 
			`;
            }
            let hotPackageJSONStr = yield HotIO_1.HotIO.readTextFile(ppath.normalize(`${__dirname}/../../package.json`));
            let hotPackageJSONObj = JSON.parse(hotPackageJSONStr);
            let hotstaqVersion = this.hotstaqVersion;
            if (hotstaqVersion === "") {
                hotstaqVersion = `^${hotPackageJSONObj.version}`;
                this.hotstaqVersion = hotstaqVersion;
            }
            if (hotstaqVersion === "link")
                hotstaqVersion = "latest";
            this.logger.info(`Generating using NPM HotStaq version: ${hotstaqVersion}`);
            let packageJSON = {
                "name": this.name,
                "description": "",
                "version": "1.0.0",
                "main": "./build/index.js",
                "scripts": {},
                "keywords": [],
                "author": "",
                "license": "ISC",
                "pkg": {
                    "scripts": [
                        "node_modules/selenium-webdriver/**/*.js"
                    ]
                },
                "dependencies": {
                    "dotenv": "^10.0.0",
                    "hotstaq": `${hotstaqVersion}`
                },
                "devDependencies": {
                    "@types/express": "^4.17.13",
                    "@types/formidable": "^3.4.5",
                    "@types/fs-extra": "^9.0.12",
                    "@types/js-cookie": "^2.2.7",
                    "@types/mocha": "^10.0.1",
                    "@types/node": "^20.11.19",
                    "@types/node-fetch": "^2.6.1",
                    "@types/selenium-webdriver": "^4.1.5",
                    "@types/uuid": "^8.3.4",
                    "@types/mime-types": "^2.1.1",
                    "@types/pg": "^8.11.10",
                    "@types/pg-pool": "^2.0.6"
                }
            };
            if (this.language === "ts") {
                packageJSON.devDependencies["ts-loader"] = "^7.0.5";
                packageJSON.devDependencies["tslib"] = "^2.6.0";
            }
            if (this.npmCommands.start === "")
                this.npmCommands.start = `node ./build/cli.js --hotsite ./HotSite.json run --server-type ${this.type}`;
            if (this.npmCommands.start !== "")
                packageJSON.scripts["start"] = this.npmCommands.start;
            if (this.npmCommands.develop === "")
                this.npmCommands.develop = `node ./build/cli.js --hotsite ./HotSite.json --development-mode run --server-type ${this.type} --web-http-port 8080`;
            if (this.npmCommands.develop !== "")
                packageJSON.scripts["develop"] = this.npmCommands.develop;
            if (this.npmCommands.test !== "")
                packageJSON.scripts["test"] = this.npmCommands.test;
            if (this.npmCommands.build === "") {
                if (this.language === "ts")
                    this.npmCommands.build = "tsc --build ./tsconfig.json";
            }
            if (this.npmCommands.build !== "")
                packageJSON.scripts["build"] = this.npmCommands.build;
            if (this.npmCommands.buildWebAPI !== "")
                packageJSON.scripts["build-web"] = this.npmCommands.buildWebAPI;
            if (this.npmCommands.buildWebAPIDebug !== "")
                packageJSON.scripts["build-web-debug"] = this.npmCommands.buildWebAPIDebug;
            if (this.npmCommands.buildDoc !== "")
                packageJSON.scripts["build-doc"] = this.npmCommands.buildDoc;
            if (this.npmCommands.buildInterfaces !== "")
                packageJSON.scripts["build-interfaces"] = this.npmCommands.buildInterfaces;
            // If this is a web only build, remove the build web scripts from packageJSON.
            if (this.type === "web") {
                if (packageJSON.scripts["build-web"] != null)
                    delete packageJSON.scripts["build-web"];
                if (packageJSON.scripts["build-web-debug"] != null)
                    delete packageJSON.scripts["build-web-debug"];
            }
            if (this.language === "ts")
                packageJSON.main = "build/index.js";
            let packageJSONstr = JSON.stringify(packageJSON, null, 2);
            yield HotIO_1.HotIO.writeTextFile(ppath.normalize(`${this.outputDir}/package.json`), packageJSONstr);
            let hotSiteJSON = {
                name: this.name,
                server: {
                    globalApi: "AppAPI",
                    serveDirectories: [{
                            route: "/",
                            localPath: "./public/"
                        }]
                },
                testing: {
                    web: {
                        testerAPIUrl: "http://127.0.0.1:8182"
                    },
                    api: {
                        maps: [
                            "AppAPI"
                        ]
                    }
                }
            };
            if (this.language === "ts") {
                if ((this.type === "web-api") || (this.type === "api")) {
                    hotSiteJSON.apis = {};
                    hotSiteJSON.apis["AppAPI"] = {
                        "jsapi": `./js/${this.name}Web_AppAPI.js`,
                        "libraryName": `${this.name}Web`,
                        "apiName": "AppAPI",
                        "filepath": "./build/AppAPI.js",
                        "map": [
                            "api:hello_world -> hi -> HiTest"
                        ]
                    };
                }
            }
            let hotSiteJSONstr = JSON.stringify(hotSiteJSON, null, "\t");
            yield HotIO_1.HotIO.writeTextFile(ppath.normalize(`${this.outputDir}/HotSite.json`), hotSiteJSONstr);
            this.logger.info(`Copying files...`);
            const projectDir = ppath.normalize(`${__dirname}/../../creator/project`);
            yield HotIO_1.HotIO.copyFiles(projectDir, ppath.normalize(`${this.outputDir}/`));
            yield HotIO_1.HotIO.moveFile(`${this.outputDir}/gitignore`, `${this.outputDir}/.gitignore`);
            yield HotIO_1.HotIO.moveFile(`${this.outputDir}/npmignore`, `${this.outputDir}/.npmignore`);
            yield this.replaceKeysInFile(ppath.normalize(`${this.outputDir}/README.md`), {
                "APPNAME": this.name,
                "BUILDSTEPS": readMeBuildSteps
            });
            if ((this.type === "web") || (this.type === "web-api")) {
                const publicDir = ppath.normalize(`${__dirname}/../../creator/public`);
                yield HotIO_1.HotIO.copyFiles(publicDir, ppath.normalize(`${this.outputDir}/public/`));
            }
            if (this.language === "ts") {
                if ((this.type === "web-api") || (this.type === "api")) {
                    const filesDir = ppath.normalize(`${__dirname}/../../creator/ts`);
                    yield HotIO_1.HotIO.copyFiles(filesDir, ppath.normalize(`${this.outputDir}/`));
                }
            }
            this.logger.info(`Finished copying files...`);
            this.logger.info(`Copying HotStaq JS files...`);
            yield this.copyLibraries(ppath.normalize(`${this.outputDir}/public/js/`));
            this.logger.info(`Finished copying HotStaq JS files...`);
            this.logger.info(`Creating VSCode files...`);
            let launchJSON = {
                "version": "0.2.0",
                "configurations": [
                    {
                        "type": "node",
                        "request": "launch",
                        "name": "Debug Web Server",
                        "program": "${workspaceFolder}/build/cli.js",
                        "skipFiles": [
                            "<node_internals>/**"
                        ],
                        "outputCapture": "std",
                        "args": [
                            "--development-mode",
                            "--hotsite", "./HotSite.json",
                            "run"
                        ],
                        "env": {}
                    }
                ]
            };
            if (this.language === "ts") {
                if ((this.type === "web-api") || (this.type === "api")) {
                    launchJSON["configurations"].push({
                        "type": "node",
                        "request": "launch",
                        "name": "Debug Web/API Server",
                        "program": "${workspaceFolder}/build/cli.js",
                        "skipFiles": [
                            "<node_internals>/**"
                        ],
                        "outputCapture": "std",
                        "args": [
                            "--development-mode",
                            "--hotsite", "./HotSite.json",
                            "run",
                            "--server-type", "web-api"
                        ],
                        "env": {}
                    }, {
                        "type": "node",
                        "request": "launch",
                        "name": "Debug API Server",
                        "program": "${workspaceFolder}/build/cli.js",
                        "skipFiles": [
                            "<node_internals>/**"
                        ],
                        "outputCapture": "std",
                        "args": [
                            "--development-mode",
                            "--hotsite", "./HotSite.json",
                            "run",
                            "--server-type", "api"
                        ],
                        "env": {}
                    });
                }
            }
            launchJSON["configurations"].push({
                "type": "node",
                "request": "launch",
                "name": "Run Web Tests",
                "skipFiles": [
                    "<node_internals>/**"
                ],
                "program": "${workspaceFolder}/build/cli.js",
                "args": [
                    "--development-mode",
                    "--hotsite", "./HotSite.json",
                    "run",
                    "--web-test"
                ],
                "env": {}
            });
            if ((this.type === "web-api") || (this.type === "api")) {
                launchJSON["configurations"].push({
                    "type": "node",
                    "request": "launch",
                    "name": "Run API Tests",
                    "skipFiles": [
                        "<node_internals>/**"
                    ],
                    "program": "${workspaceFolder}/build/cli.js",
                    "args": [
                        "--development-mode",
                        "--hotsite", "./HotSite.json",
                        "run",
                        "--api-test"
                    ],
                    "env": {}
                });
            }
            launchJSON["configurations"].push({
                "type": "pwa-node",
                "request": "attach",
                "name": "Remote Debugger",
                "skipFiles": [
                    "<node_internals>/**"
                ],
                "localRoot": "${workspaceFolder}",
                "address": "127.0.0.1",
                "port": 9229,
                "remoteRoot": `/app`
            });
            let launchJSONstr = JSON.stringify(launchJSON, null, "\t");
            yield HotIO_1.HotIO.writeTextFile(ppath.normalize(`${this.outputDir}/.vscode/launch.json`), launchJSONstr);
            let tasksJSON = {
                "version": "2.0.0",
                "tasks": []
            };
            if (this.language === "ts") {
                if ((this.type === "web-api") || (this.type === "api")) {
                    tasksJSON["tasks"].push({
                        "type": "typescript",
                        "tsconfig": "tsconfig.json",
                        "option": "watch",
                        "problemMatcher": [
                            "$tsc-watch"
                        ],
                        "group": "build",
                        "runOptions": {
                            "instanceLimit": 1,
                            "runOn": "folderOpen"
                        },
                        "label": "Build Server"
                    });
                }
            }
            let tasksJSONstr = JSON.stringify(tasksJSON, null, "\t");
            yield HotIO_1.HotIO.writeTextFile(ppath.normalize(`${this.outputDir}/.vscode/tasks.json`), tasksJSONstr);
            this.logger.info(`Finished creating VSCode files...`);
            this.logger.info(`Installing modules...`);
            yield HotIO_1.HotIO.exec(`cd ${this.outputDir} && ${this.createCommands.init}`);
            if (this.hotstaqVersion === "link") {
                this.logger.info(`Linking HotStaq...`);
                yield HotIO_1.HotIO.exec(`cd ${this.outputDir} && npm link hotstaq`);
            }
            this.logger.info(`Finished installing modules...`);
            if (this.language === "ts") {
                this.logger.info(`Transpiling TypeScript...`);
                if (this.createCommands.transpileTS !== "")
                    yield HotIO_1.HotIO.exec(`cd ${this.outputDir} && ${this.createCommands.transpileTS}`);
                this.logger.info(`Finished transpiling TypeScript...`);
            }
            this.logger.info(`Generating API JavaScript...`);
            if (this.createCommands.generateAPI !== "") {
                yield HotIO_1.HotIO.exec(`cd ${this.outputDir} && ${this.createCommands.generateAPI}`);
                yield HotStaq_1.HotStaq.wait(1000); /// @fixme Remove this temp hack...
                yield HotIO_1.HotIO.copyFile(ppath.normalize(`${this.outputDir}/build-web/${this.name}Web_AppAPI.js`), ppath.normalize(`${this.outputDir}/public/js/${this.name}Web_AppAPI.js`));
            }
            this.logger.info(`Finished generating API JavaScript...`);
            this.logger.info(`Finished creating "${this.name}"...`);
        });
    }
    /**
     * Replace keys in a file.
     */
    replaceKeysInFile(filepath, keys) {
        return __awaiter(this, void 0, void 0, function* () {
            let contents = yield HotIO_1.HotIO.readTextFile(filepath);
            for (let key in keys) {
                let value = keys[key];
                contents = HotStaq_1.HotStaq.replaceKey(contents, key, value);
            }
            yield HotIO_1.HotIO.writeTextFile(filepath, contents);
        });
    }
}
exports.HotCreator = HotCreator;
//# sourceMappingURL=HotCreator.js.map