import { execa } from 'execa';
import fs, { promises, lstatSync, readdirSync, existsSync } from 'fs';
import path from 'path';
import mergeJsonStr from 'merge-packages';
import url, { fileURLToPath } from 'url';
import ncp from 'ncp';
import { promisify } from 'util';
import { projectInstall } from 'pkg-install';
import chalk from 'chalk';
import { Listr } from 'listr2';
import arg from 'arg';
import inquirer from 'inquirer';

const baseDir = "base";

const findFilesRecursiveSync = (baseDir, criteriaFn = () => true) => {
    const subPaths = fs.readdirSync(baseDir);
    const files = subPaths.map((relativePath) => {
        const fullPath = path.resolve(baseDir, relativePath);
        return fs.lstatSync(fullPath).isDirectory()
            ? [...findFilesRecursiveSync(fullPath, criteriaFn)]
            : criteriaFn(fullPath)
                ? [fullPath]
                : [];
    });
    return files.flat();
};

// @ts-expect-error We don't have types for this probably add .d.ts file
function mergePackageJson$1(targetPackageJsonPath, secondPackageJsonPath, isDev) {
    const existsTarget = fs.existsSync(targetPackageJsonPath);
    const existsSecond = fs.existsSync(secondPackageJsonPath);
    if (!existsTarget && !existsSecond) {
        return;
    }
    const targetPackageJson = existsTarget ? fs.readFileSync(targetPackageJsonPath, "utf8") : '{}';
    const secondPackageJson = existsSecond ? fs.readFileSync(secondPackageJsonPath, "utf8") : '{}';
    const mergedPkgStr = mergeJsonStr.default(targetPackageJson, secondPackageJson);
    // Parse and reformat the merged JSON to ensure proper formatting
    const mergedPkgObj = JSON.parse(mergedPkgStr);
    const formattedPkgStr = JSON.stringify(mergedPkgObj, null, 2) + '\n';
    fs.writeFileSync(targetPackageJsonPath, formattedPkgStr, "utf8");
    if (isDev) {
        const devStr = `TODO: write relevant information for the contributor`;
        fs.writeFileSync(`${targetPackageJsonPath}.dev`, devStr, "utf8");
    }
}

const { mkdir, link } = promises;
/**
 * The goal is that this function has the same API as ncp, so they can be used
 * interchangeably.
 *
 * - clobber not implemented
 */
const linkRecursive = async (source, destination, options) => {
    const passesFilter = options?.filter === undefined
        ? true // no filter
        : typeof options.filter === 'function'
            ? options.filter(source) // filter is function
            : options.filter.test(source); // filter is regex
    if (!passesFilter) {
        return;
    }
    if (lstatSync(source).isDirectory()) {
        const subPaths = readdirSync(source);
        await Promise.all(subPaths.map(async (subPath) => {
            const sourceSubpath = path.join(source, subPath);
            const isSubPathAFolder = lstatSync(sourceSubpath).isDirectory();
            const destSubPath = path.join(destination, subPath);
            const existsDestSubPath = existsSync(destSubPath);
            if (isSubPathAFolder && !existsDestSubPath) {
                await mkdir(destSubPath);
            }
            await linkRecursive(sourceSubpath, destSubPath, options);
        }));
        return;
    }
    return link(source, destination);
};

var extensions = [
	{
		extensionFlagValue: "erc-20",
		description: "Adds support for ERC-20 token contracts, including balance checks and token transfers.",
		repository: "https://github.com/Arb-Stylus/create-stylus-extensions",
		branch: "erc-20"
	},
	{
		extensionFlagValue: "erc-721",
		description: "Adds support for ERC-721 NFT contracts, including supply, balance, listing, and transfer features.",
		repository: "https://github.com/Arb-Stylus/create-stylus-extensions",
		branch: "erc-721"
	},
	{
		extensionFlagValue: "chainlink-data-feed",
		description: "Adds support for Chainlink Data Feeds, including price and other data feeds.",
		repository: "https://github.com/Arb-Stylus/create-stylus-extensions",
		branch: "chainlink-data-feed"
	},
	{
		extensionFlagValue: "chainlink-vrf",
		description: "Adds support for Chainlink VRF, including random number generation and randomness.",
		repository: "https://github.com/Arb-Stylus/create-stylus-extensions",
		branch: "chainlink-vrf"
	}
];

function loadExtensions() {
    return extensions;
}
function findExtensionByFlag(flagValue) {
    return extensions.find((ext) => ext.extensionFlagValue === flagValue);
}

async function copyExtensionFile(extensionName, targetDirectory) {
    if (!extensionName || extensionName.trim() === "") {
        return;
    }
    const extensionConfig = findExtensionByFlag(extensionName);
    if (!extensionConfig) {
        return;
    }
    const targetPackagesDir = path.join(targetDirectory, "packages");
    if (!fs.existsSync(targetPackagesDir)) {
        return;
    }
    try {
        const tempDir = path.join(targetDirectory, ".temp-extension");
        fs.mkdirSync(tempDir, { recursive: true });
        await cloneExtensionRepository(extensionConfig, tempDir);
        await copyExtensionFiles(tempDir, targetPackagesDir, extensionConfig.extensionFlagValue);
        await mergePackageJsonFiles(tempDir, targetPackagesDir, extensionConfig.extensionFlagValue);
        await mergeRootPackageJson(tempDir, targetDirectory, extensionConfig.extensionFlagValue);
        fs.rmSync(tempDir, { recursive: true, force: true });
    }
    catch (error) {
        throw error;
    }
}
async function cloneExtensionRepository(extension, tempDir) {
    try {
        const { stdout, stderr } = await execa("git", [
            "clone",
            "--branch", extension.branch,
            "--single-branch",
            "--depth", "1",
            extension.repository,
            tempDir
        ]);
    }
    catch (error) {
        throw error;
    }
}
async function copyExtensionFiles(tempDir, targetPackagesDir, extensionName) {
    let extensionPackageDir = path.join(tempDir, "packages", extensionName);
    if (!fs.existsSync(extensionPackageDir)) {
        extensionPackageDir = path.join(tempDir, "extensions", "packages", extensionName);
    }
    if (fs.existsSync(extensionPackageDir)) {
        const targetExtensionDir = path.join(targetPackagesDir, extensionName);
        copyDirectoryRecursive(extensionPackageDir, targetExtensionDir);
    }
    let extensionPackagesDir = path.join(tempDir, "packages");
    if (!fs.existsSync(extensionPackagesDir)) {
        extensionPackagesDir = path.join(tempDir, "extensions", "packages");
    }
    if (fs.existsSync(extensionPackagesDir)) {
        const packages = fs.readdirSync(extensionPackagesDir);
        for (const packageName of packages) {
            if (packageName === extensionName) {
                continue;
            }
            const sourcePackageDir = path.join(extensionPackagesDir, packageName);
            const targetPackageDir = path.join(targetPackagesDir, packageName);
            if (fs.existsSync(targetPackageDir)) {
                mergeDirectoryRecursive(sourcePackageDir, targetPackageDir);
            }
            else {
                copyDirectoryRecursive(sourcePackageDir, targetPackageDir);
            }
        }
    }
}
async function mergePackageJsonFiles(tempDir, targetPackagesDir, extensionName) {
    let extensionPackagesDir = path.join(tempDir, "packages");
    if (!fs.existsSync(extensionPackagesDir)) {
        extensionPackagesDir = path.join(tempDir, "extensions", "packages");
    }
    if (!fs.existsSync(extensionPackagesDir)) {
        return;
    }
    const packages = fs.readdirSync(extensionPackagesDir);
    for (const packageName of packages) {
        const sourcePackageDir = path.join(extensionPackagesDir, packageName);
        const targetPackageDir = path.join(targetPackagesDir, packageName);
        if (fs.existsSync(targetPackageDir)) {
            const sourcePackageJsonPath = path.join(sourcePackageDir, "package.json");
            const targetPackageJsonPath = path.join(targetPackageDir, "package.json");
            if (fs.existsSync(sourcePackageJsonPath) && fs.existsSync(targetPackageJsonPath)) {
                mergePackageJson(sourcePackageJsonPath, targetPackageJsonPath);
            }
        }
    }
}
async function mergeRootPackageJson(tempDir, targetDirectory, extensionName) {
    let extensionRootPackageJsonPath = path.join(tempDir, "package.json");
    if (!fs.existsSync(extensionRootPackageJsonPath)) {
        extensionRootPackageJsonPath = path.join(tempDir, "extensions", "package.json");
    }
    if (!fs.existsSync(extensionRootPackageJsonPath)) {
        return;
    }
    const targetRootPackageJsonPath = path.join(targetDirectory, "package.json");
    if (fs.existsSync(targetRootPackageJsonPath)) {
        mergePackageJson(extensionRootPackageJsonPath, targetRootPackageJsonPath);
        addPackageToWorkspaces(targetRootPackageJsonPath, extensionName);
    }
}
function mergePackageJson(sourcePath, targetPath) {
    try {
        const sourcePackageJson = JSON.parse(fs.readFileSync(sourcePath, 'utf8'));
        const targetPackageJson = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
        if (sourcePackageJson.scripts && targetPackageJson.scripts) {
            targetPackageJson.scripts = { ...targetPackageJson.scripts, ...sourcePackageJson.scripts };
        }
        if (sourcePackageJson.dependencies && targetPackageJson.dependencies) {
            targetPackageJson.dependencies = { ...targetPackageJson.dependencies, ...sourcePackageJson.dependencies };
        }
        if (sourcePackageJson.devDependencies && targetPackageJson.devDependencies) {
            targetPackageJson.devDependencies = { ...targetPackageJson.devDependencies, ...sourcePackageJson.devDependencies };
        }
        if (sourcePackageJson.peerDependencies && targetPackageJson.peerDependencies) {
            targetPackageJson.peerDependencies = { ...targetPackageJson.peerDependencies, ...sourcePackageJson.peerDependencies };
        }
        fs.writeFileSync(targetPath, JSON.stringify(targetPackageJson, null, 2));
    }
    catch (error) {
        // Error handling without logging
    }
}
function addPackageToWorkspaces(packageJsonPath, packageName) {
    try {
        const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
        if (packageJson.workspaces && packageJson.workspaces.packages) {
            const workspacePath = `packages/${packageName}`;
            if (!packageJson.workspaces.packages.includes(workspacePath)) {
                packageJson.workspaces.packages.push(workspacePath);
                fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
            }
        }
    }
    catch (error) {
        // Error handling without logging
    }
}
function copyDirectoryRecursive(source, destination) {
    fs.mkdirSync(destination, { recursive: true });
    const files = fs.readdirSync(source);
    for (const file of files) {
        const sourcePath = path.join(source, file);
        const destPath = path.join(destination, file);
        const stat = fs.statSync(sourcePath);
        if (stat.isDirectory()) {
            copyDirectoryRecursive(sourcePath, destPath);
        }
        else {
            fs.copyFileSync(sourcePath, destPath);
        }
    }
}
function mergeDirectoryRecursive(source, destination) {
    if (!fs.existsSync(destination)) {
        fs.mkdirSync(destination, { recursive: true });
    }
    const files = fs.readdirSync(source);
    for (const file of files) {
        const sourcePath = path.join(source, file);
        const destPath = path.join(destination, file);
        const stat = fs.statSync(sourcePath);
        if (stat.isDirectory()) {
            mergeDirectoryRecursive(sourcePath, destPath);
        }
        else {
            fs.copyFileSync(sourcePath, destPath);
        }
    }
}

const copy = promisify(ncp);
let copyOrLink = copy;
const isTemplateRegex = /([^\/\\]*?)\.template\./;
const isPackageJsonRegex = /package\.json/;
const isYarnLockRegex = /yarn\.lock/;
const isNextGeneratedRegex = /packages\/nextjs\/generated/;
const isArgsRegex = /([^\/\\]*?)\.args\./;
const isGitKeepRegex = /\.gitkeep/;
// Additional files/directories to exclude from template copying
const excludePatterns = [
    /\.github\//, // GitHub specific files todo: add workflows/main.yml later
    /CHANGELOG\.md/, // Changelog file
    /__test.*__/, // All test directories (__test__, __tests__, etc.)
];
const copyBaseFiles = async ({ dev: isDev, extension }, basePath, targetDir) => {
    await copyOrLink(basePath, targetDir, {
        clobber: false,
        filter: (fileName) => {
            const isPackageJson = isPackageJsonRegex.test(fileName);
            const isYarnLock = isYarnLockRegex.test(fileName);
            const isNextGenerated = isNextGeneratedRegex.test(fileName);
            const isGitKeep = isGitKeepRegex.test(fileName);
            const isYourContract = /packages\/stylus\/your-contract/.test(fileName);
            // Check if file matches any exclude pattern
            const isExcluded = excludePatterns.some(pattern => pattern.test(fileName));
            const skipAlways = isPackageJson || isGitKeep || isExcluded;
            const skipDevOnly = isYarnLock || isNextGenerated;
            const skipWhenExtension = extension && isYourContract;
            const shouldSkip = skipAlways || (isDev && skipDevOnly) || skipWhenExtension;
            return !shouldSkip;
        },
    });
    ["stylus", "nextjs"].forEach(packageName => {
        const envExamplePath = path.join(basePath, "packages", packageName, ".env.example");
        const envPath = path.join(targetDir, "packages", packageName, ".env");
        if (fs.existsSync(envExamplePath)) {
            copy(envExamplePath, envPath);
        }
    });
    const basePackageJsonPaths = findFilesRecursiveSync(basePath, (path) => isPackageJsonRegex.test(path));
    basePackageJsonPaths.forEach((packageJsonPath) => {
        const partialPath = packageJsonPath.split(basePath)[1];
        mergePackageJson$1(path.join(targetDir, partialPath), path.join(basePath, partialPath), isDev);
    });
    if (isDev) {
        const baseYarnLockPaths = findFilesRecursiveSync(basePath, (path) => isYarnLockRegex.test(path));
        baseYarnLockPaths.forEach((yarnLockPath) => {
            const partialPath = yarnLockPath.split(basePath)[1];
            copy(path.join(basePath, partialPath), path.join(targetDir, partialPath));
        });
        const nextGeneratedPaths = findFilesRecursiveSync(basePath, (path) => isNextGeneratedRegex.test(path));
        nextGeneratedPaths.forEach((nextGeneratedPath) => {
            const partialPath = nextGeneratedPath.split(basePath)[1];
            copy(path.join(basePath, partialPath), path.join(targetDir, partialPath));
        });
    }
};
const processTemplatedFiles = async ({ dev: isDev, extension }, basePath, targetDir) => {
    const baseTemplatedFileDescriptors = findFilesRecursiveSync(basePath, (path) => isTemplateRegex.test(path)).map((baseTemplatePath) => ({
        path: baseTemplatePath,
        fileUrl: url.pathToFileURL(baseTemplatePath).href,
        relativePath: baseTemplatePath.split(basePath)[1],
        source: "base",
    }));
    await Promise.all(baseTemplatedFileDescriptors.map(async (templateFileDescriptor) => {
        const templateTargetName = templateFileDescriptor.path.match(isTemplateRegex)?.[1];
        const argsPath = templateFileDescriptor.relativePath.replace(isTemplateRegex, `${templateTargetName}.args.`);
        // Load the template
        const template = (await import(templateFileDescriptor.fileUrl)).default;
        if (!template) {
            throw new Error(`Template ${templateTargetName} from ${templateFileDescriptor.source} doesn't have a default export`);
        }
        if (typeof template !== "function") {
            throw new Error(`Template ${templateTargetName} from ${templateFileDescriptor.source} is not exporting a function by default`);
        }
        // Collect args from multiple sources
        const argsFileUrls = [];
        // Check for args in target directory (from extensions)
        if (extension) {
            const extensionArgsPath = path.join(targetDir, argsPath);
            if (fs.existsSync(extensionArgsPath)) {
                argsFileUrls.push(url.pathToFileURL(extensionArgsPath).href);
            }
        }
        // Load and combine all args
        const argsModules = await Promise.all(argsFileUrls.map(async (argsFileUrl) => {
            try {
                return await import(argsFileUrl);
            }
            catch (error) {
                console.warn(`Failed to load args from: ${argsFileUrl}`);
                return {};
            }
        }));
        // Combine all args into a single object
        const combinedArgs = argsModules.reduce((acc, module) => {
            return { ...acc, ...module };
        }, {});
        // Execute template with combined args
        const output = template(combinedArgs);
        const targetPath = path.join(targetDir, templateFileDescriptor.relativePath.split(templateTargetName)[0], templateTargetName);
        fs.writeFileSync(targetPath, output);
        if (isDev) {
            const devOutput = `--- TEMPLATE FILE
templates/${templateFileDescriptor.source}${templateFileDescriptor.relativePath}


--- ARGS FILES
${argsFileUrls.length > 0
                ? argsFileUrls.map(url => `\t- ${url.split("packages")[1] || url}`).join("\n")
                : "(no args files writing to the template)"}


--- RESULTING ARGS
${Object.keys(combinedArgs).length > 0
                ? Object.entries(combinedArgs)
                    .map(([key, value]) => `\t- ${key}:\t${JSON.stringify(value)}`)
                    .join("\n")
                : "(no args sent for the template)"}
`;
            fs.writeFileSync(`${targetPath}.dev`, devOutput);
        }
    }));
};
async function copyTemplateFiles(options, templateDir, targetDir) {
    copyOrLink = options.dev ? linkRecursive : copy;
    const basePath = path.join(templateDir, baseDir);
    // 1. Copy base template to target directory
    await copyBaseFiles(options, basePath, targetDir);
    // 2. Copy extension files if extension is provided
    if (options.extension) {
        await copyExtensionFile(options.extension, targetDir);
    }
    // 3. Process templated files with extension args
    await processTemplatedFiles(options, basePath, targetDir);
    // 4. Clean up template and args files
    await cleanupTemplateFiles(targetDir);
    // 5. Initialize git repo to avoid husky error
    await execa("git", ["init"], { cwd: targetDir });
    await execa("git", ["checkout", "-b", "main"], { cwd: targetDir });
}
async function cleanupTemplateFiles(targetDir) {
    const basePath = targetDir;
    // Find all template and args files
    const templateFiles = findFilesRecursiveSync(basePath, (path) => isTemplateRegex.test(path));
    const argsFiles = findFilesRecursiveSync(basePath, (path) => isArgsRegex.test(path));
    // Delete template files
    templateFiles.forEach((templatePath) => {
        try {
            fs.unlinkSync(templatePath);
        }
        catch (error) {
            console.warn(`Failed to delete template file: ${templatePath}`);
        }
    });
    // Delete args files
    argsFiles.forEach((argsPath) => {
        try {
            fs.unlinkSync(argsPath);
        }
        catch (error) {
            console.warn(`Failed to delete args file: ${argsPath}`);
        }
    });
}

async function createProjectDirectory(projectName) {
    // Check if directory already exists
    if (fs.existsSync(projectName)) {
        // If directory exists, check if it's empty
        if (fs.readdirSync(projectName).length > 0) {
            throw new Error(`Directory ${projectName} already exists and is not empty. Cannot continue.`);
        }
        // If directory exists and is empty, we can proceed (or do nothing here, as it's already created and empty)
        // For clarity, we can return true or simply let the function continue if no further action is needed.
        // In this case, since the directory exists and is empty, the goal is achieved.
        return true;
    }
    try {
        const result = await execa("mkdir", [projectName]);
        if (result.failed) {
            throw new Error("There was a problem running the mkdir command");
        }
    }
    catch (error) {
        throw new Error(`Failed to create directory: ${error instanceof Error ? error.message : String(error)}`);
    }
    return true;
}

async function installPackages(targetDir, options) {
    // Condition to check if 'devnet' is included and only update submodules
    // if (options.extensions?.includes("starknet-native")) {
    // }
    return projectInstall({
        cwd: targetDir,
        prefer: "yarn",
    });
}

async function createFirstGitCommit(targetDir) {
    try {
        await execa("git", ["add", "-A"], { cwd: targetDir });
        await execa("git", ["commit", "-m", "Initial commit with 🏗️ Scaffold-Stylus", "--no-verify"], { cwd: targetDir });
    }
    catch (e) {
        throw new Error("Failed to initialize git repository", {
            cause: e?.stderr ?? e,
        });
    }
}

async function prettierFormat(targetDir) {
    try {
        const nextjsPath = path.join(targetDir, "packages/nextjs");
        const result = await execa("yarn", ["format"], { cwd: nextjsPath });
        if (result.failed) {
            throw new Error("There was a problem running the format command");
        }
    }
    catch (error) {
        throw new Error("Failed to format Next.js project", { cause: error });
    }
    return true;
}

async function setConfigNetworkToSepolia(targetDirectory) {
    const scaffoldConfigPath = path.join(targetDirectory, "packages", "nextjs", "scaffold.config.ts");
    if (!fs.existsSync(scaffoldConfigPath)) {
        return;
    }
    try {
        let content = fs.readFileSync(scaffoldConfigPath, 'utf8');
        // Replace arbitrumNitro with arbitrumSepolia for chainlink extensions
        content = content.replace(/targetNetworks:\s*\[chains\.arbitrumNitro\]/, 'targetNetworks: [chains.arbitrumSepolia]');
        fs.writeFileSync(scaffoldConfigPath, content);
    }
    catch (error) {
        console.warn(`Failed to modify scaffold.config.ts: ${error}`);
    }
}

async function renderOutroMessage(options) {
    let message = `
  \n
  ${chalk.bold.green("Congratulations!")} Your project has been scaffolded! 🎉

  ${chalk.bold("Next steps:")}
  
  ${chalk.dim("cd")} ${options.directory}
  `;
    message += `
    \t${chalk.bold("Start the local development node")}
    \t${chalk.dim("yarn")} chain
    `;
    message += `
    \t${chalk.bold("In a new terminal window, deploy your contracts")}
    \t${chalk.dim("yarn")} deploy
   `;
    message += `
  \t${chalk.bold("In a new terminal window, start the frontend")}
  \t${chalk.dim("yarn")} start
  `;
    message += `
  ${chalk.bold.green("Thanks for using Scaffold-Stylus 🙏, Happy Building!")}
  `;
    console.log(message);
}

async function createProject(options) {
    console.log(`\n`);
    const currentFileUrl = import.meta.url;
    const templateDirectory = path.resolve(decodeURI(fileURLToPath(currentFileUrl)), "../../templates");
    const targetDirectory = path.resolve(process.cwd(), options.directory);
    const tasks = new Listr([
        {
            title: `📁 Create project directory ${targetDirectory}`,
            task: async () => await createProjectDirectory(options.directory),
        },
        {
            title: `🚀 Creating a new Scaffold-Stylus app in ${chalk.green.bold(options.directory)}`,
            task: async (ctx, task) => {
                if (ctx.options.extension) {
                    task.title = `🚀 Creating a new Scaffold-Stylus app${ctx.options.extension
                        ? ` with ${chalk.green.bold(ctx.options.extension)} extension`
                        : ""} in ${chalk.green.bold(ctx.options.directory)}`;
                }
                await copyTemplateFiles(options, templateDirectory, targetDirectory);
            },
        },
        {
            title: `⚙️ Configuring scaffold for ${chalk.green.bold(options.extension || "default")} extension`,
            task: async (ctx, task) => {
                if (ctx.options.extension && (ctx.options.extension === "chainlink-vrf" || ctx.options.extension === "chainlink-data-feed")) {
                    await setConfigNetworkToSepolia(targetDirectory);
                }
            },
        },
        {
            title: `📦 Installing dependencies with yarn, this could take a while`,
            task: async (ctx, task) => {
                if (!!ctx.options.install) {
                    await installPackages(targetDirectory);
                }
                else {
                    task.skip("Manually skipped");
                }
            },
        },
        {
            title: "🪄 Formatting Next.js files with prettier",
            task: async (ctx, task) => {
                if (!!ctx.options.install) {
                    await prettierFormat(targetDirectory);
                }
                else {
                    task.skip("Skipping because prettier install was skipped");
                }
            },
        },
        {
            title: `📡 Initializing Git repository`,
            task: async () => await createFirstGitCommit(targetDirectory),
        },
    ], { ctx: { options } });
    try {
        await tasks.run();
        renderOutroMessage(options);
    }
    catch (error) {
        console.log("%s Error occurred", chalk.red.bold("ERROR"), error);
        console.log("%s Exiting...", chalk.red.bold("Uh oh! 😕 Sorry about that!"));
    }
}

// TODO update smartContractFramework code with general extensions
function parseArgumentsIntoOptions(rawArgs) {
    const args = arg({
        "--skip-install": Boolean,
        "-s": "--skip-install",
        "--dev": Boolean,
        "--dir": String,
        "-d": "--dir",
        "--extension": String,
        "-e": "--extension",
    }, {
        argv: rawArgs.slice(2).map((a) => a.toLowerCase()),
    });
    const skipInstall = args["--skip-install"] ?? null;
    const dev = args["--dev"] ?? false; // info: use false avoid asking user
    const directory = args["--dir"] ?? null;
    const extension = args["--extension"] ?? null;
    return {
        directory,
        install: skipInstall ? false : null,
        dev,
        extension,
    };
}

// default values for unspecified args
const defaultOptions = {
    directory: "./my-dapp-example",
    install: true,
    dev: false};
async function promptForMissingOptions(options) {
    const cliAnswers = Object.fromEntries(Object.entries(options).filter(([key, value]) => value !== null));
    const extensions = loadExtensions();
    extensions.map(ext => ({
        name: `${ext.extensionFlagValue} - ${ext.description}`,
        value: ext.extensionFlagValue,
    }));
    const questions = [
        {
            type: "input",
            name: "directory",
            message: "Where do you want to save this new project? Choose ./ (root folder) or provide a new folder name.",
            default: defaultOptions.directory,
            validate: (value) => value.length > 0,
        },
        {
            type: "confirm",
            name: "install",
            message: "Install dependencies?",
            default: defaultOptions.install,
        },
    ];
    const answers = await inquirer.prompt(questions, cliAnswers);
    const mergedOptions = {
        directory: options.directory ?? answers.directory,
        install: options.install ?? answers.install,
        dev: options.dev ?? defaultOptions.dev,
        extension: options.extension ?? answers.extension,
    };
    return mergedOptions;
}

const TITLE_TEXT = `
 ${chalk.bold.blue("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+")}
 ${chalk.bold.blue("| Create Scaffold-Stylus app  |")}
 ${chalk.bold.blue("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+")}
`;
function renderIntroMessage() {
    console.log(TITLE_TEXT);
}

async function cli(args) {
    renderIntroMessage();
    const rawOptions = parseArgumentsIntoOptions(args);
    const options = await promptForMissingOptions(rawOptions);
    await createProject(options);
}

export { cli };
//# sourceMappingURL=cli.js.map
