const path = require('path');
const dedent = require('dedent');
const argv = require('minimist')(process.argv.slice(2));

const { sync } = require('./helpers/cli');
const { warn, error } = require('./helpers/log');
const { getPublicPath } = require('../webpack/helpers/source');

const isSilent = argv._.includes('help') || argv._.includes('init') || argv._.includes('print-config');

const readJSON = (file) => {
    const fileName = `${file}.json`;

    if (file === 'env' && !isSilent) {
        warn('[DEPREACTION NOTICE] Please rename your file env.json to appConfig.json');
    }

    try {
        return require(path.join(process.cwd(), fileName));
    } catch (e) {
        if (!isSilent) {
            warn(`Missing file ${fileName}`);
        }
        if (/SyntaxError/.test(e.stack)) {
            error(e);
        }
    }
};

const getGitBranch = () => {
    try {
        const { stdout = '' } = sync('git describe --all');
        return stdout.trim();
    } catch (e) {
        return '';
    }
};

const getGitCommitHash = () => {
    try {
        const { stdout = '' } = sync('git rev-parse HEAD');
        return stdout.trim();
    } catch (e) {
        return '';
    }
};

const getGitTagVersion = (applicationName) => {
    try {
        const { stdout = '' } = sync(`git describe --abbrev=0 --match=${applicationName}*`);
        return stdout.trim();
    } catch (e) {
        return '';
    }
};

/**
 * Clean ex. proton-mail@4.x.x to 4.x.x
 */
const getVersionNumberFromTag = (tag) => {
    return tag.replace(/[^@]*@/g, '');
}

/**
 * Extract the config of a project
 * - env: from env.json for sentry, and some custom config for the app
 *     appConfig: {
 *         name: 'Web',
 *         etc.
 *     }
 * - pkg: from package.json for sentry
 * @return {Object}   { env: Object, pkg: Object }
 */
const CONFIG_ENV = (() => {
    const pkg = require(path.join(process.cwd(), 'package.json'));
    // @todo load value from the env as it's done for proton-i19n
    return {
        env: readJSON('appConfig') || readJSON('env') || {},
        pkg,
    };
})();

/**
 * Read the configuration for translations, it's a file generated by the CI
 * <locale>: <name of the locale>
 */
const LOCALES = (() => {
    try {
        // Local dependency relative to the application
        return require(require.resolve('proton-translations/config/locales.json', { paths: [process.cwd()]}));
    } catch (e) {
        if (!process.argv.includes('print-config')) {
            warn('No po/locales.json available yet');
        }
        return {};
    }
})();

const ENV_CONFIG = Object.keys(CONFIG_ENV.env).reduce(
    (acc, key) => {
        if (key === 'appConfig') {
            acc.app = CONFIG_ENV.env[key];
            return acc;
        }
        const { api, secure } = CONFIG_ENV.env[key];
        if (api) {
            acc.api[key] = api;
        }
        if (secure) {
            acc.secure[key] = secure;
        }
        return acc;
    },
    { api: {}, secure: {}, pkg: CONFIG_ENV.pkg, app: {} }
);

const API_TARGETS = {
    prod: 'https://mail.protonmail.com/api',
    local: 'https://protonmail.dev/api',
    localhost: 'https://localhost/api',
    build: '/api',
    ...ENV_CONFIG.api,
};

/**
 * Yargs creates an array if you gives many flags
 * Ensure to take only the last one
 * @param  {String|Array} api
 * @return {Object}
 */
const getApi = (api) => {
    const parse = (api) => {
        if (!Array.isArray(api)) {
            return api || 'proxy';
        }

        const { length, [length - 1]: latest } = api.filter(Boolean);
        return latest || 'proxy';
    };

    const value = parse(api);

    // We can do --api=https://mail.protonmail.com/api and it's only for dev, so we can stop here
    if (value.includes('https') || value.includes('/api')) {
        return { value, url: value };
    }

    // Because we can "extend" via + -> --api dev+proxy = dev env but with /api as API url
    const urlList = value.split('+');
    const url = urlList.reduce((apiUrl, apiKey) => API_TARGETS[apiKey] || apiUrl, API_TARGETS.prod);

    return { value, url, first: urlList[0] };
};

function main({ api = 'dev' }) {
    const appName = ENV_CONFIG.app.appName || ENV_CONFIG.pkg.name;
    if (!appName) {
        throw new Error('Missing app name');
    }

    const branch = process.env.CI_COMMIT_REF_NAME || getGitBranch();
    const commit = process.env.CI_COMMIT_SHA || getGitCommitHash();
    const version = getVersionNumberFromTag(process.env.CI_COMMIT_TAG || getGitTagVersion(appName));

    const { url: apiUrl } = getApi(api);

    const json = {
        appName,
        version: ENV_CONFIG.app.version || ENV_CONFIG.pkg.version || version || '4.0.0',
        locales: LOCALES,
        apiUrl,
    };

    const isProduction = process.env.NODE_ENV === 'production';
    const SENTRY_DSN = isProduction ? ENV_CONFIG.app.sentry || '' : '';

    const PUBLIC_APP_PATH = getPublicPath(argv);

    const buildData = {
        version: json.version,
        commit,
        branch,
        date: new Date().toGMTString()
    };

    const config = dedent`
    export const CLIENT_TYPE = ${ENV_CONFIG.app.clientType || 1};
    export const CLIENT_SECRET = '${ENV_CONFIG.app.clientSecret || ''}';
    export const APP_VERSION = '${buildData.version}';
    export const COMMIT = '${buildData.commit}';
    export const BRANCH = '${buildData.branch}';
    export const DATE_VERSION = '${buildData.date}';
    export const APP_NAME = '${json.appName}';
    export const API_URL = '${apiUrl}';
    export const LOCALES = ${JSON.stringify(LOCALES)};
    export const API_VERSION = '3';
    export const VERSION_PATH = '${PUBLIC_APP_PATH}assets/version.json';
    export const SENTRY_DSN = '${SENTRY_DSN}';
    `;

    return {
        config,
        buildData,
        apiUrl,
        json,
        path: path.join(process.cwd(), 'src', 'app', 'config.ts'),
    };
}

module.exports = main;

@@ -1549,16 +1549,17 @@
 , '');%0A%7D
+;
 %0A%0A/**%0A *
@@ -2402,16 +2402,17 @@
 s.cwd()%5D
+ 
 %7D));%0A   
@@ -4647,60 +4647,8 @@
 ion:
- ENV_CONFIG.app.version %7C%7C ENV_CONFIG.pkg.version %7C%7C
  ver
@@ -4662,11 +4662,12 @@
  '4.
-0.0
+9.99
 ',%0A 
@@ -5027,16 +5027,17 @@
 String()
+,
 %0A    %7D;%0A

Update fallback version