import { TBundleSizeBaseLine, TComparisonRes, TComparisonResLine } from '../types';
import { baseLineToString } from './baseLineUtils';

export function convertComparisonResultToMd(
    params: {
        currentBaseLine: TBundleSizeBaseLine | undefined,
        newBaseLine: TBundleSizeBaseLine
        comparisonResult: TComparisonRes,
    },
) {
    const { currentBaseLine, newBaseLine, comparisonResult } = params;
    const isExceedsLimits = Object.keys(comparisonResult).reduce((acc, rowId) => {
        if (!comparisonResult[rowId].withinThreshold) {
            return true;
        }
        return acc;
    }, false);

    const baselineVersion = currentBaseLine ? `v${currentBaseLine.version}` : 'baseline not found';
    const headerRemap = {
        baseLineSize: `Baseline Size<br />(${baselineVersion})`,
        size: 'Size',
        diffLabel: 'Diff',
        withinThreshold: 'Within<br />Threshold',
        thresholdLabel: 'Threshold<br />(min - max)',
    };
    const formatHeader = (h: keyof TComparisonResLine) => {
        return headerRemap[h] || h;
    };

    const tableMd = formatMdTable(
        comparisonResult,
        formatHeader,
        (h, v: any) => {
            if (h === 'withinThreshold') {
                return v ? ':ok:' : ':no_entry:';
            }
            if (h === 'baseLineSize' || h === 'size') {
                return String(normalizeSizeNumber(v.js + v.css));
            }
            return v;
        },
    );
    /*
     * The "CI Status: error" part is used by "qualityGate.yml" to mark the workflow failed when limits are exceeded.
     * So, if you want to change it, then please make sure that "qualityGate.yml" is updated as well.
     */
    const generatedBy = 'Generated by: track-bundle-size';
    const ciStatus = `CI Status: ${isExceedsLimits ? 'error' : 'ok'}`;
    const descriptionMd = [
        generatedBy,
        `Generated at: ${new Date().toUTCString()}`,
        'Bundle size diff (in kBytes). Not gzipped. Both CSS & JS included.',
        `Baseline: ${baselineVersion} ${currentBaseLine ? `(${currentBaseLine.timestamp})` : ''}`,
        `${ciStatus}\n`,
    ].join('<br>');

    const newBaseLineStr = baseLineToString(newBaseLine);
    const newBaseLineMd = formatNewBaseLine(newBaseLineStr);

    return `${descriptionMd}\n${tableMd}\n${newBaseLineMd}`;
}

function formatMdTable(
    obj: TComparisonRes,
    formatHeader: (h: keyof TComparisonResLine) => string,
    formatValue: (h: keyof TComparisonResLine, v: TComparisonResLine[keyof TComparisonResLine]) => string,
) {
    const attrs: (keyof TComparisonResLine)[] = ['baseLineSize', 'size', 'diffLabel', 'withinThreshold', 'thresholdLabel'];
    const header = '| Module |' + attrs.map(formatHeader).join('|') + '|';
    const headerSep = '|:-----:|' + attrs.map(() => ':-----:').join('|') + '|';
    const rows = Object.keys(obj).reduce<string[]>((acc, rowId) => {
        const rowContent = attrs.map((a) => {
            return formatValue(a, obj[rowId][a]);
        }).join('|');
        acc.push(`|${rowId}|${rowContent}|`);
        return acc;
    }, []);
    return `${header}\n${headerSep}\n${rows.join('\n')}`;
}

function formatNewBaseLine(baseLine: string) {
    return [
        '<details>',
        '<summary>new sizes (raw)</summary>',
        '',
        'To set the sizes as a new baseline, you can copy/paste next content to the ```uui-build/config/bundleSizeBaseLine.json``` and commit the file.',
        '',
        '```json',
        baseLine,
        '```',
        '</details>',
    ].join('\n');
}

function normalizeSizeNumber(num: number) {
    return Number(Number(num).toFixed(2));
}
