const { Errors, colors, allOfType } = require("svcorelib");
const { join, resolve } = require("path");

const { getEnv, getProp } = require("../src/env");
const parseJokes = require("../src/parseJokes");

const languages = require("../src/languages");
const translate = require("../src/translate");
const settings = require("../settings");
const { readdir } = require("fs-extra");

const col = colors.fg;
const { exit } = process;


/** @typedef {import("svcorelib").Stringifiable} Stringifiable */
/** @typedef {import("./types").SubmissionInfoResult} SubmissionInfoResult */
/** @typedef {import("../src/types/languages").LangCode} LangCode */


async function run()
{
    try
    {
        try
        {
            await languages.init();

            await translate.init();

            await parseJokes.init();
        }
        catch(err)
        {
            console.log(`\n${col.red}Error while initializing:${col.rst}${err instanceof Error ? `${err.message}\n${err.stack}` : `\n${err.toString()}`}\n`);
            exit(1);
        }

        /**
         * Decorates an array value with colors and other stuff
         * @param {Stringifiable[]} val
         */
        const n = val => {
            const ln = val.length;

            const lhs = `(${ln > 0 ? "" : col.yellow}${val.length}${col.rst})`;
            const rhs = `${col.green}${val.join(`${col.rst}, ${col.green}`)}${col.rst}`;
            return `${lhs}:  ${rhs}`;
        };

        /**
         * Decorates a value with colors and other stuff
         * @param {number|string} val
         */
        const v = val => {
            const valCol = typeof val === "number" ? (val > 0 ? col.green : col.yellow) : col.green;
            const value = Array.isArray(val) && allOfType(val, "string") ? val.join(`${col.rst}, ${valCol}`) : val;

            return `      ${valCol}${value}${col.rst}`;
        };


        const { jokes, subm, http } = await getInfo("submissions");

        /** The lines that get printed to the console to display JokeAPI's info */
        const lines = [
            `${col.blue}${settings.info.name}${col.rst} v${settings.info.version} [${getEnv(true)}] - Info`,
            ``,
            `${col.blue}Jokes:${col.rst}`,
            `  Total amount:  ${v(jokes.totalAmt)}`,
            `  Joke languages ${n(jokes.languages)}`,
            ``,
            `${col.blue}Submissions:${col.rst}`,
            `  Amount:   ${v(subm.amount)}`,
            `  Languages ${n(subm.languages)}`,
            ``,
            `${col.blue}HTTP Server:${col.rst}`,
            `  Port:    ${v(http.port)}`,
            `  BaseURL: ${v(http.baseUrl)}`,
        ];

        process.stdout.write(`\n${lines.join("\n")}\n\n`);

        exit(0);
    }
    catch(err)
    {
        console.log(`\n${col.red}Error while displaying info:${col.rst}${err instanceof Error ? `${err.message}\n${err.stack}` : `\n${err.toString()}`}\n`);
        exit(1);
    }
}

/**
 * Returns all information about JokeAPI
 */
async function getInfo()
{
    const { allJokes } = parseJokes;

    /** @type {LangCode[]} */
    const jokeLangs = Object.keys(allJokes.getJokeCountPerLang());

    const { submCount, submLangs } = await getSubmissionInfo();

    return {
        /** Internal jokes */
        jokes: {
            totalAmt: allJokes._jokeCount,
            languages: jokeLangs,
        },
        /** Joke submissions */
        subm: {
            amount: submCount,
            languages: submLangs,
        },
        /** HTTP server */
        http: {
            port: getProp("httpPort"),
            baseUrl: getProp("baseUrl"),
        },
        // ...
    }
}

/**
 * Resolves with some info about the submissions JokeAPI has received
 * @returns {Promise<SubmissionInfoResult, Error>}
 */
function getSubmissionInfo()
{
    return new Promise(async (res, rej) => {
        try
        {
            const submBasePath = resolve(settings.jokes.jokeSubmissionPath);

            const langs = await readdir(submBasePath);

            const submFolders = langs.map(lang => join(submBasePath, lang));

            const submissionFiles = [];

            for await(const folder of submFolders)
                (await readdir(folder))
                    .forEach(file => submissionFiles.push(file));

            return res({
                submCount: submissionFiles.length,
                submLangs: langs,
            });
        }
        catch(err)
        {
            return rej(err);
        }
    });
}


//#SECTION on execute

(() => {
    try
    {
        if(!process.stdin.isTTY)
            throw new Errors.NoStdinError("The process doesn't have an stdin channel to read input from");
        else
            run();
    }
    catch(err)
    {
        console.error(`${col.red}${err.message}${col.rst}\n${err.stack}\n`);

        exit(0);
    }
})();
