import { head, multiply, prop } from 'rambda';
import { byNum, desc } from 'sort-lib';
import { combineColumnsInArray, divide, exists } from './utils.js';
const stageHasName = (stageName) => (stage) => stage.name.toLowerCase().includes(stageName.toLowerCase());
export const pipelineHasStageNamed = (stageName) => (pipeline) => pipeline.stageCounts.some(stageHasName(stageName));
export const pipelineUsesStageNamed = (stageName) => (pipeline) => {
    const matchingStages = pipeline.stageCounts.filter(stageHasName(stageName));
    if (!matchingStages.length)
        return false;
    return matchingStages.some(stage => stage.successful > 0);
};
export const pipelineHasStartingArtifact = (pipeline) => Object.entries(pipeline.repos).length > 0;
export const normalizePolicy = (policies) => {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
    return ({
        minimumNumberOfReviewers: {
            count: (_b = (_a = policies.minimumNumberOfReviewers) === null || _a === void 0 ? void 0 : _a.count) !== null && _b !== void 0 ? _b : 0,
            isOptional: (_d = (_c = policies.minimumNumberOfReviewers) === null || _c === void 0 ? void 0 : _c.isOptional) !== null && _d !== void 0 ? _d : false,
        },
        workItemLinking: {
            state: Boolean(policies.workItemLinking),
            isOptional: (_f = (_e = policies.workItemLinking) === null || _e === void 0 ? void 0 : _e.isOptional) !== null && _f !== void 0 ? _f : false,
        },
        builds: {
            state: Boolean(policies.builds),
            isOptional: (_h = (_g = policies.builds) === null || _g === void 0 ? void 0 : _g.isOptional) !== null && _h !== void 0 ? _h : false,
        },
        commentRequirements: {
            state: Boolean(policies.commentRequirements),
            isOptional: (_k = (_j = policies.commentRequirements) === null || _j === void 0 ? void 0 : _j.isOptional) !== null && _k !== void 0 ? _k : false,
        },
        requireMergeStrategy: {
            state: Boolean(policies.requireMergeStrategy),
            isOptional: (_m = (_l = policies.requireMergeStrategy) === null || _l === void 0 ? void 0 : _l.isOptional) !== null && _m !== void 0 ? _m : false,
        },
    });
};
export const policyStatus = (aggregatedPolicy, key) => {
    if (key === 'minimumNumberOfReviewers') {
        if (aggregatedPolicy.minimumNumberOfReviewers.count === 0)
            return 'fail';
        if (aggregatedPolicy.minimumNumberOfReviewers.isOptional ||
            aggregatedPolicy.minimumNumberOfReviewers.count < 1) {
            return 'fail';
        }
        if (aggregatedPolicy.minimumNumberOfReviewers.count >= 1 &&
            !aggregatedPolicy.minimumNumberOfReviewers.isOptional) {
            return 'pass';
        }
        return 'fail';
    }
    if (aggregatedPolicy[key].isOptional && aggregatedPolicy[key].state) {
        return 'warn';
    }
    if (!aggregatedPolicy[key].isOptional && aggregatedPolicy[key].state) {
        return 'pass';
    }
    return 'fail';
};
export const fullPolicyStatus = (policy) => {
    const states = Object.keys(policy)
        .filter(key => key !== 'requireMergeStrategy')
        .map(key => policyStatus(policy, key));
    if (states.every(c => c === 'pass')) {
        return 'pass';
    }
    if (states.includes('fail')) {
        return 'fail';
    }
    return 'warn';
};
export const pipelineMeetsBranchPolicyRequirements = (policyForBranch) => (pipeline) => Object.keys(pipeline.repos).length === 0
    ? false
    : Object.entries(pipeline.repos)
        .reduce((acc, [repoId, { branches }]) => {
        if (branches.length === 0) {
            acc.push('fail');
            return acc;
        }
        branches.forEach(branch => {
            acc.push(fullPolicyStatus(policyForBranch(repoId, branch)));
        });
        return acc;
    }, [])
        .every(p => p === 'pass');
export const masterDeploysCount = (pipelines) => pipelines.reduce((acc, pipeline) => {
    acc.total += pipeline.attempts.total;
    acc.count += pipeline.attempts.master;
    return acc;
}, { count: 0, total: 0 });
export const isPipelineInGroup = (groupName, repos) => (pipeline) => pipeline.name.toLowerCase().startsWith(groupName.toLowerCase())
    ? true
    : Object.values(pipeline.repos).some(r => repos.includes(r.name));
const usageByEnvironment = (environments) => (pipeline) => {
    if (!environments)
        return;
    return environments.reduce((acc, env) => {
        const matchingStage = head(pipeline.stageCounts.filter(stageHasName(env)).sort(desc(byNum(prop('total')))));
        if (!matchingStage)
            return acc;
        acc[env] = { successful: matchingStage.successful, total: matchingStage.total };
        return acc;
    }, {});
};
export const totalUsageByEnvironment = (environments) => (pipelines) => Object.fromEntries(Object.entries(pipelines
    .map(usageByEnvironment(environments))
    .filter(exists)
    .reduce((acc, item) => {
    Object.entries(item).forEach(([env, { successful, total }]) => {
        var _a, _b;
        acc[env] = {
            successful: (((_a = acc[env]) === null || _a === void 0 ? void 0 : _a.successful) || 0) + successful,
            total: (((_b = acc[env]) === null || _b === void 0 ? void 0 : _b.total) || 0) + total,
        };
    });
    return acc;
}, {})).sort(([a], [b]) => {
    const envs = environments === null || environments === void 0 ? void 0 : environments.map(e => e.toLowerCase());
    if (!envs) {
        return 0;
    }
    return envs.indexOf(a.toLowerCase()) - envs.indexOf(b.toLowerCase());
}));
export const masterOnlyReleasesByWeek = (pipelines) => combineColumnsInArray((a, b) => {
    if (!a)
        return b;
    if (!b)
        return a;
    return { total: a.total + b.total, master: a.master + b.master };
})(pipelines.flatMap(p => p.attempts).map(a => a.byWeek)).map(a => {
    if (!a)
        return;
    // eslint-disable-next-line unicorn/no-useless-undefined
    return divide(a.master, a.total).map(multiply(100)).map(Math.round).getOr(undefined);
});
