#!/usr/bin/env node
import React from 'react';
import { render } from 'ink';
import { Command } from 'commander';
import chalk from 'chalk';
import inquirer from 'inquirer';
import axios from 'axios';
import fs from 'fs';
import { exec } from 'child_process';
import { promisify } from 'util';
import os from 'os';
import App from './app.mjs';
import path from 'path';
import { codepushAction } from './codepush.mjs';
import { compileAction } from './compile.mjs';
import { createAction } from './create.mjs';
const execAsync = promisify(exec);
const program = new Command();
program.name("aptl")
    .description("Apptile command line utitlity")
    .version("0.1.0");
async function getUser() {
    try {
        const homeDir = os.homedir();
        const apptileCliDir = path.join(homeDir, '.apptile-cli');
        const stateFilePath = path.join(apptileCliDir, 'apptile-cli-state.mjson');
        const rawdata = fs.readFileSync(stateFilePath, { encoding: "utf8" });
        const parsed = JSON.parse(rawdata);
        const { status, data } = await axios.get("https://api.apptile.io/api/users/me", {
            headers: {
                cookie: parsed.cookie
            }
        });
        if (status === 200) {
            return { user: data, cookie: parsed.cookie };
        }
        else {
            return { user: null, cookie: "" };
        }
    }
    catch (err) {
        const msg = serializeAxiosError(err);
        if (msg) {
            console.log(msg);
        }
        else {
            console.log(err);
        }
        return { user: null, cookie: "" };
    }
}
function getStateFilePath() {
    const homeDir = os.homedir();
    const apptileCliDir = path.join(homeDir, '.apptile-cli');
    return path.join(apptileCliDir, 'apptile-cli-state.mjson');
}
function readStateFile() {
    try {
        const stateFilePath = getStateFilePath();
        if (!fs.existsSync(stateFilePath)) {
            return {};
        }
        const rawdata = fs.readFileSync(stateFilePath, { encoding: "utf8" });
        return JSON.parse(rawdata);
    }
    catch (err) {
        return {};
    }
}
function writeStateFile(data) {
    const homeDir = os.homedir();
    const apptileCliDir = path.join(homeDir, '.apptile-cli');
    const stateFilePath = path.join(apptileCliDir, 'apptile-cli-state.mjson');
    if (!fs.existsSync(apptileCliDir)) {
        fs.mkdirSync(apptileCliDir, { recursive: true });
    }
    fs.writeFileSync(stateFilePath, JSON.stringify(data, null, 2));
}
function serializeAxiosError(err) {
    if (err && err.response && err.code) {
        let errorBody = err.response.data;
        if (typeof errorBody === "object") {
            errorBody = JSON.stringify(err.response.data);
        }
        let serialized = `calling: ${err.request.protocol}//${err.request.host}${err.request.path}
${chalk.red(err.code)}
${chalk.yellow(err.response.status)} ${chalk.yellow(err.response.statusText)}`;
        if (errorBody) {
            serialized += `\n\n${errorBody}`;
        }
        return serialized;
    }
    else {
        return null;
    }
}
program.command("login")
    .description("Login to app.apptile.io platform.")
    .arguments("<email>")
    .action(async function (email) {
    try {
        const { user } = await getUser();
        if (user) {
            console.log(chalk.green("Already logged in as: " + user.firstname + " " + user.lastname));
            return;
        }
    }
    catch (err) {
        console.error(err);
    }
    const answers = await inquirer.prompt([{
            type: 'password',
            name: 'password',
            message: `Enter password for ${email}: `,
        }]);
    try {
        const { status, headers, statusText } = await axios.post("https://api.apptile.io/api/users/login", {
            email: email,
            password: answers.password,
        }, {
            headers: {
                "Content-Type": "application/json"
            },
        });
        if (status === 201) {
            console.log(chalk.green("User logged in successfully"));
        }
        else {
            console.log(chalk.red("Login failed!!"), status, statusText);
        }
        const setCookieHeader = headers["set-cookie"];
        if (setCookieHeader && setCookieHeader[0]) {
            const cookie = setCookieHeader[0].split(";")[0];
            // Read existing state to preserve SDK_PATH
            const existingState = readStateFile();
            const newState = { ...existingState, cookie };
            writeStateFile(newState);
        }
        else {
            console.log(chalk.red("The api call succeeded but no login token was recieved"));
        }
    }
    catch (err) {
        const serializedErr = serializeAxiosError(err);
        if (serializedErr) {
            console.log(serializedErr);
        }
        else {
            console.error(err);
        }
    }
});
program.command("logout")
    .description("Logout from cli.")
    .action(async function () {
    // Read existing state to preserve SDK_PATH
    const existingState = readStateFile();
    const { cookie, ...stateWithoutCookie } = existingState;
    writeStateFile(stateWithoutCookie);
    console.log(chalk.green("Successfully logged out"));
});
async function getManifest(appId) {
    try {
        const { data } = await axios.get(`https://api.apptile.io/api/v2/app/${appId}/manifest`);
        if (!data.gitRepo) {
            data.gitRepo = 'git@github.com:clearsight-dev/rn-pilgrim-app.git';
        }
        return data;
    }
    catch (err) {
        const msg = serializeAxiosError(err);
        console.log(msg);
        return null;
    }
}
program.command("clone")
    .description("Clone an app into the current directory.")
    .arguments("[appid]")
    .option("--regen-config", "Only regenerate the apptile configuration without cloning")
    .action(async function (appid, options) {
    try {
        const { cookie } = await getUser();
        if (!cookie) {
            console.log(chalk.red("Not logged in!"));
            process.exit(1);
        }
        // Check if SDK_PATH is set
        const state = readStateFile();
        if (!state.SDK_PATH) {
            console.log(chalk.red("Error: SDK path is not set. Please run 'aptl sdkpath set' first."));
            process.exit(1);
        }
        const currentDir = process.cwd();
        // If --regen-config is set, only regenerate config and skip cloning
        if (options.regenConfig) {
            console.log(chalk.blue("Regenerating apptile configuration only..."));
            // Check if apptile.config.mjson exists in current directory
            const configPath = path.resolve(currentDir, "apptile.config.mjson");
            if (!fs.existsSync(configPath)) {
                console.log(chalk.red("Error: apptile.config.mjson not found in current directory."));
                console.log(chalk.red("This is not a valid apptile clone directory."));
                process.exit(1);
            }
            // Read existing config to get APP_ID
            let existingConfig;
            try {
                const existingConfigRaw = fs.readFileSync(configPath, { encoding: "utf8" });
                existingConfig = JSON.parse(existingConfigRaw);
            }
            catch (err) {
                console.log(chalk.red("Error: Could not read existing apptile.config.mjson"));
                console.log(chalk.red("This is not a valid apptile clone directory."));
                process.exit(1);
            }
            if (!existingConfig.APP_ID) {
                console.log(chalk.red("Error: APP_ID not found in apptile.config.mjson"));
                console.log(chalk.red("This is not a valid apptile clone directory."));
                process.exit(1);
            }
            const targetAppId = existingConfig.APP_ID;
            console.log(chalk.blue(`Found APP_ID: ${targetAppId}`));
            // Get manifest for the app
            const manifest = await getManifest(targetAppId);
            if (!manifest) {
                console.log(chalk.red(`Could not get manifest for app ${targetAppId}!`));
                process.exit(1);
            }
            console.log(chalk.blue(`Regenerating config for app: ${manifest.name} (${targetAppId})`));
            // Regenerate apptile configuration with full config
            try {
                const buildConfigResponse = await axios.get(`https://api.apptile.io/build-system/api/build/${targetAppId}/buildConfig`, {
                    headers: {
                        "x-app-id": targetAppId,
                        cookie: cookie
                    },
                });
                const fullConfig = {
                    "-comment-": "This file is generated by cli. You can edit it to use different configs, but will be overwritten on regeneration.",
                    ...buildConfigResponse.data,
                    SDK_PATH: state.SDK_PATH,
                    APP_ID: targetAppId,
                    APPTILE_BACKEND_URL: 'https://api.apptile.io',
                    APPCONFIG_SERVER_URL: 'https://appconfigs.apptile.io',
                    APPTILE_BUILD_MANAGER_URL: 'https://api.apptile.io/build-system/api',
                };
                console.log(chalk.blue("Writing complete apptile.config.mjson"));
                fs.writeFileSync(configPath, JSON.stringify(fullConfig, null, 2));
                console.log(chalk.green("Apptile configuration regenerated successfully"));
            }
            catch (configError) {
                console.log(chalk.red("Error: Could not regenerate apptile configuration"));
                const msg = serializeAxiosError(configError);
                if (msg) {
                    console.log(msg);
                }
                else {
                    console.log(configError);
                }
                process.exit(1);
            }
            return;
        }
        // Original cloning logic (when --regen-config is not set)
        // Validate that appid is provided for cloning
        if (!appid) {
            console.log(chalk.red("Error: App ID is required for cloning. Usage: aptl clone <appid>"));
            process.exit(1);
        }
        // ensure current directory is empty
        const entries = fs.readdirSync(currentDir);
        if (entries.length > 0) {
            console.log(chalk.red("Error: Current directory is not empty. Please run this command in an empty directory."));
            process.exit(1);
        }
        // get the app manifest
        const manifest = await getManifest(appid);
        if (!manifest) {
            console.log(chalk.red("Could not get appid!"));
            process.exit(1);
        }
        console.log(chalk.blue(`Cloning app: ${manifest.name} (${appid})`));
        // Clone the repository
        if (manifest.gitRepo) {
            console.log(chalk.blue(`Cloning from git repository: ${manifest.gitRepo}`));
            await execAsync(`git clone --depth=1 ${manifest.gitRepo} .`);
        }
        else {
            console.log(chalk.blue("No git repository found, cloning from default seed repository"));
            await execAsync(`git clone --depth=1 git@github.com:clearsight-dev/apptile-seed.git .`);
        }
        // Create initial apptile.config.mjson with SDK_PATH
        const initialConfig = {
            "-comment-": "Partial config. Set apptilecookie and hit generate appconfig in cli to get the rest.",
            APP_ID: manifest.uuid,
            APPTILE_BACKEND_URL: 'https://api.apptile.io',
            APPCONFIG_SERVER_URL: 'https://appconfigs.apptile.io',
            APPTILE_BUILD_MANAGER_URL: 'https://api.apptile.io/build-system/api',
            SDK_PATH: state.SDK_PATH
        };
        console.log(chalk.blue("Writing initial apptile.config.mjson"));
        fs.writeFileSync(path.resolve(currentDir, "apptile.config.mjson"), JSON.stringify(initialConfig, null, 2));
        // Regenerate apptile configuration with full config
        console.log(chalk.blue("Regenerating apptile configuration..."));
        try {
            const buildConfigResponse = await axios.get(`https://api.apptile.io/build-system/api/build/${manifest.uuid}/buildConfig`, {
                headers: {
                    "x-app-id": manifest.uuid,
                    cookie: cookie
                },
            });
            const fullConfig = {
                "-comment-": "This file is generated by cli. You can edit it to use different configs, but will be overwritten on regeneration.",
                ...buildConfigResponse.data,
                SDK_PATH: state.SDK_PATH,
                APP_ID: manifest.uuid,
                APPTILE_BACKEND_URL: 'https://api.apptile.io',
                APPCONFIG_SERVER_URL: 'https://appconfigs.apptile.io',
                APPTILE_BUILD_MANAGER_URL: 'https://api.apptile.io/build-system/api',
            };
            console.log(chalk.blue("Writing complete apptile.config.mjson"));
            fs.writeFileSync(path.resolve(currentDir, "apptile.config.mjson"), JSON.stringify(fullConfig, null, 2));
            console.log(chalk.green("Apptile configuration regenerated successfully"));
        }
        catch (configError) {
            console.log(chalk.yellow("Warning: Could not regenerate full apptile configuration. Using partial config."));
            console.log(chalk.yellow("You can regenerate it later using the CLI."));
            // Keep the initial partial config that was already written
        }
        console.log(chalk.green(`Successfully cloned app ${manifest.name} (${appid})`));
    }
    catch (err) {
        console.log(chalk.red("Error during cloning:"), err);
        process.exit(1);
    }
});
program.command("status")
    .description("Current status. This depends on the directory inside which you run the utility")
    .action(async function () {
    try {
        const { user } = await getUser();
        if (user) {
            console.log(chalk.green(`Logged in as: ${user.firstname} ${user.lastname} (${user.email})`));
        }
        else {
            console.log(chalk.red("Not logged in"));
        }
        // Check SDK path status
        const state = readStateFile();
        if (state.SDK_PATH) {
            console.log(chalk.green(`SDK Path: ${state.SDK_PATH}`));
        }
        else {
            console.log(chalk.yellow("SDK Path: Not set"));
        }
    }
    catch (err) {
        console.log(chalk.red("Not logged in"));
    }
});
program.command("sdkpath")
    .description("Manage SDK path configuration")
    .option("--set", "Set the SDK path")
    .option("--get", "Get the current SDK path")
    .action(async function (options) {
    const { set, get } = options;
    // Ensure exactly one option is provided
    if ((set && get) || (!set && !get)) {
        console.log(chalk.red("Error: You must specify exactly one option: --set or --get"));
        process.exit(1);
    }
    if (get) {
        const state = readStateFile();
        if (state.SDK_PATH) {
            console.log(chalk.green(`Current SDK Path: ${state.SDK_PATH}`));
        }
        else {
            console.log(chalk.yellow("SDK Path is not set"));
        }
        return;
    }
    if (set) {
        const answers = await inquirer.prompt([{
                type: 'input',
                name: 'sdkPath',
                message: 'Enter the path to ApptileSDK: ',
                validate: function (input) {
                    if (!input.trim()) {
                        return 'Path cannot be empty';
                    }
                    // Check if path exists
                    const expandedPath = input.replace(/^~/, os.homedir());
                    if (!fs.existsSync(expandedPath)) {
                        return 'Path does not exist. Please enter a valid path.';
                    }
                    return true;
                }
            }]);
        // Expand ~ to home directory
        const expandedPath = answers.sdkPath.replace(/^~/, os.homedir());
        const absolutePath = path.resolve(expandedPath);
        // Read existing state and update with SDK_PATH
        const existingState = readStateFile();
        const newState = { ...existingState, SDK_PATH: absolutePath };
        writeStateFile(newState);
        console.log(chalk.green(`SDK Path set to: ${absolutePath}`));
    }
});
program.command("codepush")
    .description("Show and update bundleId's for the app")
    .option("--show-current", "Show current bundle IDs from apptile.config.mjson")
    .option("--list-available-bundles <type>", "List available bundles (plugins|ios|navigators|android)")
    .action(codepushAction);
program.command("compile")
    .description("Compile plugins in the current apptile project")
    .action(compileAction);
program.command("create")
    .description("Create a new plugin or navigator")
    .option("--type <type>", "Type of component to create (plugin|navigator)")
    .action(createAction);
program.command("tui")
    .description("Just show the tui")
    .action(function () {
    render(React.createElement(App, { name: "" }));
});
program.parse(process.argv);
