import { head, prop } from 'rambda';
import { byDate, desc } from 'sort-lib';
import { pastDate } from '../../utils.js';
// Get list of available metrics at <sonar-host>/api/metrics/search
export const requiredMetrics = [
    'blocker_violations',
    'bugs',
    'code_smells',
    'cognitive_complexity',
    'branch_coverage',
    'conditions_to_cover',
    'coverage',
    'critical_violations',
    'complexity',
    'duplicated_blocks',
    'duplicated_files',
    'duplicated_lines',
    'duplicated_lines_density',
    'line_coverage',
    'ncloc',
    'ncloc_language_distribution',
    'lines_to_cover',
    'quality_gate_details',
    'alert_status',
    'reliability_rating',
    'security_rating',
    'sqale_index',
    'sqale_rating',
    'uncovered_conditions',
    'uncovered_lines',
    'vulnerabilities',
    'files',
];
const isMeasureName = (name) => (measure) => measure.metric === name;
export const formatLoc = (loc) => {
    if (!loc)
        return;
    return loc.split(';').map(langGroup => {
        const [lang, loc] = langGroup.split('=');
        return { lang, loc: Number(loc) };
    });
};
const combineLoc = (locs) => {
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const filtered = locs.filter(Boolean).flatMap(x => x);
    const combinedSet = new Map();
    filtered.forEach(({ lang, loc }) => {
        combinedSet.set(lang, combinedSet.has(lang)
            ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                combinedSet.get(lang) + loc
            : loc);
    });
    return Array.from(combinedSet.entries()).map(([lang, loc]) => ({ lang, loc }));
};
const parseQualityGateStatus = (gateLabel) => {
    switch (gateLabel) {
        case 'OK': {
            return 'pass';
        }
        case 'WARN': {
            return 'warn';
        }
        case 'ERROR': {
            return 'fail';
        }
        default: {
            return 'unknown';
        }
    }
};
const sonarAnalysisGetter = (sonarAnalysis) => {
    const { measures, url, lastAnalysisDate, name } = sonarAnalysis;
    const findMeasure = (name) => { var _a; return (_a = measures.find(isMeasureName(name))) === null || _a === void 0 ? void 0 : _a.value; };
    const measureAsNumber = (name) => {
        const measure = findMeasure(name);
        return measure ? Number(measure) : undefined;
    };
    const qualityGateDetails = JSON.parse(findMeasure('quality_gate_details') || '{}');
    const qualityGateMetric = (metricName) => {
        var _a;
        const metric = (_a = qualityGateDetails.conditions) === null || _a === void 0 ? void 0 : _a.find(({ metric }) => metric === metricName);
        if (!metric)
            return;
        return {
            value: (metric === null || metric === void 0 ? void 0 : metric.actual) ? Number(metric.actual) : undefined,
            op: (metric === null || metric === void 0 ? void 0 : metric.op) ? metric.op.toLowerCase() : undefined,
            level: (metric === null || metric === void 0 ? void 0 : metric.error) ? Number(metric.error) : undefined,
            status: parseQualityGateStatus(metric.level),
        };
    };
    return {
        url,
        name,
        lastAnalysisDate,
        measureAsNumber,
        qualityGateMetric,
        qualityGateStatus: parseQualityGateStatus(qualityGateDetails.level),
    };
};
const uptillWeeks = [12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1].map(weekIndex => {
    const weekEnd = pastDate(`${(weekIndex - 1) * 7} days`);
    return (d) => d <= weekEnd;
});
export default (sonarAnalyses) => {
    if (!sonarAnalyses)
        return { codeQuality: null };
    return {
        languages: combineLoc(sonarAnalyses.map(sonarAnalysis => {
            var _a;
            return formatLoc((_a = sonarAnalysis.measures.find(isMeasureName('ncloc_language_distribution'))) === null || _a === void 0 ? void 0 : _a.value);
        })),
        codeQuality: sonarAnalyses.map(sonarAnalysis => {
            var _a;
            const { name, url, lastAnalysisDate, measureAsNumber, qualityGateMetric, qualityGateStatus, } = sonarAnalysisGetter(sonarAnalysis);
            return {
                url,
                name,
                lastAnalysisDate,
                qualityGateName: sonarAnalysis.qualityGateName,
                files: measureAsNumber('files'),
                complexity: {
                    cyclomatic: measureAsNumber('complexity'),
                    cognitive: measureAsNumber('cognitive_complexity'),
                },
                quality: {
                    gate: qualityGateStatus,
                    securityRating: qualityGateMetric('security_rating'),
                    coverage: qualityGateMetric('coverage'),
                    duplicatedLinesDensity: qualityGateMetric('duplicated_lines_density'),
                    blockerViolations: qualityGateMetric('blocker_violations'),
                    codeSmells: qualityGateMetric('code_smells'),
                    criticalViolations: qualityGateMetric('critical_violations'),
                },
                coverage: {
                    byTests: measureAsNumber('coverage'),
                    line: measureAsNumber('line_coverage'),
                    linesToCover: measureAsNumber('lines_to_cover'),
                    uncoveredLines: measureAsNumber('uncovered_lines'),
                    branch: measureAsNumber('branch_coverage'),
                    conditionsToCover: measureAsNumber('conditions_to_cover'),
                    uncoveredConditions: measureAsNumber('uncovered_conditions'),
                },
                reliability: {
                    rating: measureAsNumber('reliability_rating'),
                    bugs: measureAsNumber('bugs'),
                },
                security: {
                    rating: measureAsNumber('security_rating'),
                    vulnerabilities: measureAsNumber('vulnerabilities'),
                },
                duplication: {
                    blocks: measureAsNumber('duplicated_blocks'),
                    files: measureAsNumber('duplicated_files'),
                    lines: measureAsNumber('duplicated_lines'),
                    linesDensity: measureAsNumber('duplicated_lines_density'),
                },
                maintainability: {
                    rating: measureAsNumber('sqale_rating'),
                    techDebt: measureAsNumber('sqale_index'),
                    codeSmells: measureAsNumber('code_smells'),
                },
                oldestFoundSample: (_a = head(sonarAnalysis.qualityGateHistory.sort(desc(byDate(prop('date')))))) === null || _a === void 0 ? void 0 : _a.date.toISOString(),
                qualityGateByWeek: uptillWeeks.map(isUptillWeek => {
                    const latestInWeek = head(sonarAnalysis.qualityGateHistory
                        .filter(({ date }) => isUptillWeek(date))
                        .sort(desc(byDate(prop('date')))));
                    return latestInWeek ? parseQualityGateStatus(latestInWeek.value) : null;
                }),
            };
        }),
    };
};
