#!/usr/bin/env node
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const _2019_1 = __importDefault(require("ajv/dist/2019"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const helpers_1 = require("yargs/helpers");
const yargs_1 = __importDefault(require("yargs/yargs"));
const contractSchemaJsonParser_1 = require("./codegen/contractSchemaJsonParser");
const mainContractGen_1 = require("./codegen/mainContractGen");
const jsonSchemaGen_1 = require("./codegen/jsonSchemaGen");
const contractSchema_1 = require("./codegen/contractSchema");
const child_process_1 = require("child_process");
const wizardServer_1 = require("./wizardServer");
const userContractGen_1 = require("./codegen/userContractGen");
const utils_1 = require("./codegen/utils");
const argv = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
    .command("validate <jsonFile>", "Validate a JSON metadata schema file", (yargs) => {
    yargs.positional("jsonFile", {
        describe: "Path to the JSON file",
        type: "string",
    });
}, validateJson)
    .command("generate <configFiles..>", "Generate patchwork contracts", (yargs) => {
    yargs
        .positional("configFiles", {
        describe: "Path to the JSON or TS files",
        type: "string",
    })
        .option("output", {
        alias: "o",
        type: "string",
        description: "Output directory for the generated Solidity files",
    })
        .option("rootdir", {
        alias: "r",
        type: "string",
        description: "Root directory for the TS files (defaults to 'src')",
    });
}, generateSolidity)
    .command("wizard", "Launch the Patchwork Wizard", {}, () => {
    (0, wizardServer_1.launchWizardApp)();
})
    .demandCommand(1, "You must provide a valid command")
    .help("h")
    .alias("h", "help")
    .argv;
function tryValidate(jsonFile, schemaFile) {
    try {
        const jsonData = require(path_1.default.resolve(jsonFile));
        const schemaData = require(schemaFile);
        const ajv = new _2019_1.default();
        const validate = ajv.compile(schemaData);
        if (validate(jsonData)) {
            return true;
        }
        return validate.errors;
    }
    catch (error) {
        console.error("Error reading JSON or schema file:", error.message);
    }
}
function validateJson(argv) {
    const jsonFile = argv.jsonFile;
    const t1 = tryValidate(jsonFile, "../src/patchwork-contract-config.schema.json");
    // TODO need separate commands to validate metadata schemas as one can bury errors in the other
    //const t2 = tryValidate(jsonFile, "../src/patchwork-metadata.schema.json")
    if (t1 === true) {
        console.log("The JSON file is a valid Patchwork contract configuration.");
    }
    else {
        console.log("The JSON file is not a valid Patchwork contract config");
        console.log("Contract Config Validation Errors:", t1);
        // console.log("Metadata Schema Validation Errors:", t2);
    }
}
function generateSolidity(argv) {
    const configFiles = argv.configFiles;
    const outputDir = argv.output || process.cwd();
    const rootDir = argv.rootdir || "src";
    const tmpout = "tmpout";
    for (const configFile of configFiles) {
        try {
            let schema;
            let solidityGenFilename;
            let solidityUserFilename;
            let jsonFilename;
            if (configFile.endsWith(".ts")) {
                try {
                    const result = (0, child_process_1.execSync)(`tsc --outdir ${tmpout} ${configFile}`);
                    console.log("TSC compile success");
                    console.log(result.toString());
                }
                catch (err) {
                    console.log("Error", err.message);
                    console.log("output", err.stdout.toString());
                    console.log("stderr", err.stderr.toString());
                }
                const jsConfigFile = path_1.default.dirname(configFile).replace(rootDir, tmpout) + path_1.default.sep + path_1.default.basename(configFile, ".ts") + ".js";
                const t = require(path_1.default.resolve(jsConfigFile)).default;
                schema = new contractSchema_1.ContractSchemaImpl(t);
                fs_1.default.rmSync(tmpout, { recursive: true });
            }
            else {
                if (!configFile.endsWith(".json")) {
                    throw new Error("Invalid file type. Please provide a JSON or TS file.");
                }
                const validated = tryValidate(configFile, "../src/patchwork-contract-config.schema.json");
                if (validated !== true) {
                    console.log(`${configFile} did not validate`, validated);
                    process.exit(1);
                }
                const jsonData = require(path_1.default.resolve(configFile));
                schema = (0, contractSchemaJsonParser_1.parseJson)(jsonData);
            }
            schema.validate();
            solidityGenFilename = (0, utils_1.cleanAndCapitalizeFirstLetter)(schema.name) + "Generated.sol";
            solidityUserFilename = (0, utils_1.cleanAndCapitalizeFirstLetter)(schema.name) + ".sol";
            jsonFilename = (0, utils_1.cleanAndCapitalizeFirstLetter)(schema.name) + "-schema.json";
            const solidityCode = new mainContractGen_1.MainContractGen().gen(schema);
            let outputPath = path_1.default.join(outputDir, solidityGenFilename);
            fs_1.default.writeFileSync(outputPath, solidityCode);
            console.log(`Solidity gen file generated at ${outputPath}`);
            const solidityUserCode = new userContractGen_1.UserContractGen().gen(schema);
            outputPath = path_1.default.join(outputDir, solidityUserFilename);
            if (fs_1.default.existsSync(outputPath)) {
                console.log(`Output file ${outputPath} already exists. Skipping overwrite.`);
            }
            else {
                fs_1.default.writeFileSync(outputPath, solidityUserCode);
                console.log(`Solidity user file generated at ${outputPath}`);
            }
            const jsonSchema = new jsonSchemaGen_1.JSONSchemaGen().gen(schema);
            outputPath = path_1.default.join(outputDir, jsonFilename);
            fs_1.default.writeFileSync(outputPath, jsonSchema);
            console.log(`JSON Schema file generated at ${outputPath}`);
        }
        catch (error) {
            console.error("Error generating Solidity file:", error.message);
        }
    }
}
