#!/usr/bin/env node
import { option } from "commander";
import { CaseInfo, SearchOptions } from "../sdk/dto";
import TestItSDK from "../sdk/testit";
const log4js = require("log4js");
const logger = log4js.getLogger();
const readline = require("readline");
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});
const loadingSpinner = require('loading-spinner');
const { Command } = require('commander');
const fs = require('fs');
const program = new Command();

program.version('0.0.1');
program
    .option('-s, --suiteName [suite name]', 'test id  or suite name is required with check option, eg: Atlas')
    .option('-i, --id [case id]', 'case id  or suite name is required with check option, eg: JPT-64401')
    .option('-st, --subType [sub type]', 'query field sub type: E2E')
    .option('-p, --projectName [project name]', 'project name is required', "Jupiter")
    .option('-e, --export [output path]', 'export test cases files', "test/fixtures/")
    .option('-t, --template [template file name]', 'template file path', "./src/templates/JupiterTemplate.ts.txt")
    .option('-c, --check', 'sync with suite name or testid and print report in console')
    .option('-r, --range [range]', 'update time range: 1d/1w/1m')
    .option('-v, --verbose', 'show detail log in console')
    .parse(process.argv);

program.helpOption('-h, --HELP', 'read more information');

const options = program.opts();

if (!options.suiteName && !options.testId) {
    throw new Error("At least one parameter is required for suite name and test id!");
}


if (!options.username) {
    rl.question("Please enter your username:", function (username) {
        rl.stdoutMuted = true;

        rl.question(`Please enter ${username}'s password to login TestIt:`, function (password) {
            options.username = username;
            options.password = password;
            rl.close();
        });
        rl._writeToOutput = function _writeToOutput(stringToWrite) {
            if (rl.stdoutMuted) {
                rl.output.write("*");
            }
            else {
                rl.output.write(stringToWrite);
            }
        };
    });

    rl.on("close", () => {
        console.log("\r\n");

        log4js.configure({
            appenders: { console: { type: 'console' } },
            categories: { default: { appenders: ['console'], level: options.verbose ? 'debug' : 'info' } }
        });

        if (options.check) {
            logger.warn(`only check case info!`);
        }
        const TESTIT_ENDPOINT = 'https://testit.ringcentral.com';
        const testItSdk = new TestItSDK(TESTIT_ENDPOINT);
        console.log("login to testid");
        loadingSpinner.start(100, {
            clearChar: true
        });
        testItSdk.login(options.username, options.password).then(async () => {
            loadingSpinner.stop();
            const searchOption: SearchOptions = {
                suiteName: options.suiteName,
                projectName: options.projectName,
                subtype: options.subType ? options.subType.split(",") : undefined
            }
            const query = await testItSdk.generateQuery(searchOption);
            logger.info(`[search cases] start :${JSON.stringify(searchOption)}`);
            loadingSpinner.start(100, {
                clearChar: true
            });
            const response = await testItSdk.searchTestCasesByQuery(query, 'TEST_SUITES', searchOption.suiteName);
            // format and print console dashboard
            let total = 0;
            const print = (items, prefix) => {
                let str = "";
                items.forEach(item => {
                    if (item.type === "suite") {
                        let caseTotal = 0;
                        item.children.forEach(child => {
                            if (child.type !== "suite") {
                                caseTotal++;
                            }
                        })
                        str += `${prefix}|- ${item.name} ${item.children && caseTotal > 0 ? caseTotal : ""}\r\n`;
                    } else {
                        total += 1;
                    }
                    if (item.children && item.type === "suite") {
                        str += print(item.children, prefix + "\t");
                    }
                })
                return str;
            };
            const treeString = print(response, "\t");

            logger.info(`cases created/updated total ${total}`);
            loadingSpinner.stop();
            // rl.question("Did you want to print the detail cases number in tree structure? (Y/N , default Y):", (r) => {
            // if (r !== "N") {
            console.log(`${treeString}`);
            // }
            // rl.close();
            // })
            if (options.check) {
                return;
            }
            console.time("handleResponse");
            console.log(`preparing for case file generate`);
            loadingSpinner.start(100, {
                clearChar: true
            });
            if (response.length == 0 || response == null) { throw new Error("could not found any matched case infomation."); }
            const cases: CaseInfo[] = await testItSdk.handleResponse(response);
            console.timeEnd("handleResponse");
            logger.info(`[search finished] matched cases total: ${cases.length}`)

            // generate all cases files
            const templatePath = options.template;
            let templateString;
            if (options.template === undefined) {
                templateString = fs.readFileSync("../templates/Default.txt", "UTF-8", function (err: any) {
                    throw new Error("Can't not find default.txt");
                });
            } else {
                templateString = fs.readFileSync(templatePath, "UTF-8", function (err: any) {
                    throw new Error(`Can't not find ${templatePath}`);
                });
            }
            loadingSpinner.stop();
            logger.info(`start generate case file with template into folder:${options.export}`)
            loadingSpinner.start(100, {
                clearChar: true
            });
            const fileGenerateTask = [];
            for (const item of cases) {
                fileGenerateTask.push(
                    new Promise<void>(async resolve => {
                        await testItSdk.storeFileInTree(item, templatePath, templateString);
                        resolve();
                    })
                );
            }
            //Promise all storage
            await Promise.all(fileGenerateTask);
            loadingSpinner.stop();
            logger.info(`[Store finished] Total Store ${fileGenerateTask.length} files`);
        }).catch(e => {
            logger.error(`[login failed] ${e.message}`);
        });
    });
}
