import { head, last, omit, prop, sum } from 'rambda';
import { z } from 'zod';
import { exists } from '../../shared/utils.js';
import { configForProject } from '../config.js';
import { inDateRange } from './helpers.js';
import { conformsToBranchPolicies } from './policy-configuration.js';
import { getMinimalReleaseDefinitions, ReleaseDefinitionModel, } from './release-definitions.js';
import { ReleaseModel } from './mongoose-models/ReleaseEnvironment.js';
import { fromContext, queryContextInputParser } from './utils.js';
import { getRepoIdsForTeamNames } from './teams.js';
export const pipelineFiltersInput = {
    queryContext: queryContextInputParser,
    searchTerm: z.string().optional(),
    nonMasterReleases: z.boolean().optional(),
    notStartingWithBuildArtifact: z.boolean().optional(),
    stageNameContaining: z.string().optional(),
    stageNameUsed: z.string().optional(),
    notConfirmingToBranchPolicies: z.boolean().optional(),
    teams: z.array(z.string()).optional(),
};
export const pipelineFiltersInputParser = z.object(pipelineFiltersInput);
const filterNotStartingWithBuildArtifact = (notStartingWithBuildArtifact) => {
    if (!notStartingWithBuildArtifact) {
        return {};
    }
    return { 'artifacts.0': { $exists: false } };
};
const filterRepos = async (collectionName, project, teams) => {
    return !teams || teams.length === 0
        ? {}
        : {
            'artifacts.definition.repositoryId': {
                $in: await getRepoIdsForTeamNames(collectionName, project, teams),
            },
        };
};
const addExactRepoSearch = (searchTerm) => {
    if (!searchTerm)
        return [];
    const repoSearch = searchTerm.match(/^repo:"(.*)"$/);
    if (!repoSearch)
        return [];
    const repoName = repoSearch[1];
    return [{ $match: { 'artifacts.definition.repositoryName': repoName } }];
};
const addFilteredEnvsField = (ignoreStagesBefore) => ignoreStagesBefore
    ? [
        {
            $addFields: {
                considerStagesAfter: {
                    $indexOfArray: [
                        {
                            $map: {
                                input: '$environments',
                                as: 'env',
                                in: {
                                    $regexMatch: {
                                        input: '$$env.name',
                                        regex: ignoreStagesBefore,
                                        options: 'i',
                                    },
                                },
                            },
                        },
                        true,
                    ],
                },
            },
        },
        {
            $addFields: {
                filteredEnvs: {
                    $cond: {
                        if: {
                            $or: [
                                { $eq: ['$considerStagesAfter', -1] },
                                { $eq: ['$considerStagesAfter', null] },
                            ],
                        },
                        then: '$environments',
                        else: {
                            $slice: [
                                '$environments',
                                '$considerStagesAfter',
                                { $subtract: [{ $size: '$environments' }, '$considerStagesAfter'] },
                            ],
                        },
                    },
                },
            },
        },
    ]
    : [{ $addFields: { filteredEnvs: '$environments' } }];
const addHasGoneAhead = {
    $addFields: {
        hasGoneAhead: {
            $anyElementTrue: {
                $map: {
                    input: '$filteredEnvs',
                    as: 'env',
                    in: { $ne: ['$$env.status', 'notStarted'] },
                },
            },
        },
    },
};
const filterNonMasterReleases = (nonMasterReleases) => {
    if (!nonMasterReleases) {
        return [];
    }
    return [
        {
            $match: {
                artifacts: { $elemMatch: { 'definition.branch': { $ne: 'refs/heads/master' } } },
            },
        },
        { $match: { filteredEnvs: { $elemMatch: { status: { $ne: 'notStarted' } } } } },
    ];
};
const doesStageExist = (stage) => ({
    $anyElementTrue: {
        $map: {
            input: '$environments',
            as: 'env',
            in: {
                $regexMatch: {
                    input: '$$env.name',
                    regex: new RegExp(stage.toLowerCase(), 'gi'),
                },
            },
        },
    },
});
const isStageUsed = (stage) => ({
    $anyElementTrue: {
        $map: {
            input: '$environments',
            as: 'env',
            in: {
                $and: [
                    {
                        $regexMatch: {
                            input: '$$env.name',
                            regex: new RegExp(stage.toLowerCase(), 'gi'),
                        },
                    },
                    { $ne: ['$$env.status', 'notStarted'] },
                ],
            },
        },
    },
});
const isStageSuccessful = (stage) => ({
    $anyElementTrue: {
        $map: {
            input: '$environments',
            as: 'env',
            in: {
                $and: [
                    {
                        $regexMatch: {
                            input: '$$env.name',
                            regex: new RegExp(stage.toLowerCase(), 'gi'),
                        },
                    },
                    { $eq: ['$$env.status', 'succeeded'] },
                ],
            },
        },
    },
});
const filterStageNameUsed = (stageNameUsed) => stageNameUsed
    ? [
        { $addFields: { isStageUsed: isStageUsed(stageNameUsed) } },
        { $match: { isStageUsed: true } },
    ]
    : [];
/**
 * Note: This function doesn't account for options.notConfirmingToBranchPolicies!!!
 * That parameter needs an entirely different approach, so is not implemented here.
 */
const createFilter = async (options) => {
    const { queryContext, nonMasterReleases, 
    /* notConfirmingToBranchPolicies, */
    searchTerm, notStartingWithBuildArtifact, stageNameContaining, stageNameUsed, teams, } = options;
    const { collectionName, project, startDate, endDate } = fromContext(queryContext);
    const releaseDefns = await getMinimalReleaseDefinitions(collectionName, project, searchTerm, stageNameContaining);
    const projectConfig = configForProject(collectionName, project);
    const ignoreStagesBefore = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.releasePipelines.ignoreStagesBefore;
    return [
        {
            $match: {
                collectionName,
                project,
                modifiedOn: inDateRange(startDate, endDate),
                releaseDefinitionId: { $in: releaseDefns.map(prop('id')) },
                ...filterNotStartingWithBuildArtifact(notStartingWithBuildArtifact),
                ...(await filterRepos(collectionName, project, teams)),
            },
        },
        ...addExactRepoSearch(searchTerm),
        ...addFilteredEnvsField(ignoreStagesBefore),
        ...filterNonMasterReleases(nonMasterReleases),
        ...filterStageNameUsed(stageNameUsed),
    ];
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const forAllArtifacts = (inClause) => ({
    $and: [
        { $ne: [{ $size: '$artifacts' }, 0] },
        {
            $allElementsTrue: {
                $map: {
                    input: '$artifacts',
                    as: 'artifact',
                    in: inClause,
                },
            },
        },
    ],
});
const addStagesToHighlight = (collectionName, project) => {
    var _a;
    const stagesToHighlight = (_a = configForProject(collectionName, project)) === null || _a === void 0 ? void 0 : _a.releasePipelines.stagesToHighlight;
    if (!stagesToHighlight) {
        return {};
    }
    return stagesToHighlight.reduce((acc, stage) => ({
        ...acc,
        [`${stage}:exists`]: doesStageExist(stage),
        [`${stage}:used`]: isStageUsed(stage),
    }), {});
};
const incIfTrue = (condition) => ({ $sum: { $cond: [condition, 1, 0] } });
const incIfNonZero = (field) => ({
    $sum: { $cond: [{ $gt: [field, 0] }, 1, 0] },
});
const createSummary = (collectionName, project) => {
    const projectConfig = configForProject(collectionName, project);
    return [
        {
            $group: {
                _id: '$releaseDefinitionId',
                runCount: { $count: {} },
                lastEnvDeploys: incIfTrue('$deployedToLastEnvironment'),
                lastEnvSuccesfulDeploys: incIfTrue({
                    $and: ['$deployedToLastEnvironment', '$successfulDeployToLastEnvironment'],
                }),
                startsWithArtifact: incIfTrue('$startsWithArtifact'),
                ...projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.releasePipelines.stagesToHighlight.reduce((acc, item) => ({
                    ...acc,
                    [`${item}:exists`]: { $sum: incIfTrue(`$${item}:exists`) },
                    [`${item}:used`]: { $sum: incIfTrue(`$${item}:used`) },
                }), {}),
                masterOnly: incIfTrue('$masterOnly'),
            },
        },
        {
            $group: {
                _id: null,
                runCount: { $sum: '$runCount' },
                pipelineCount: { $count: {} },
                lastEnvDeploys: { $sum: '$lastEnvDeploys' },
                lastEnvSuccesfulDeploys: { $sum: '$lastEnvSuccesfulDeploys' },
                startsWithArtifact: incIfNonZero('$startsWithArtifact'),
                ...projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.releasePipelines.stagesToHighlight.reduce((acc, item) => ({
                    ...acc,
                    [`${item}:exists`]: incIfNonZero(`$${item}:exists`),
                    [`${item}:used`]: incIfNonZero(`$${item}:used`),
                }), {}),
                masterOnly: { $sum: '$masterOnly' },
            },
        },
        {
            $project: {
                runCount: '$runCount',
                pipelineCount: '$pipelineCount',
                lastEnv: (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.environments)
                    ? {
                        envName: last(projectConfig.environments),
                        deploys: '$lastEnvDeploys',
                        successful: '$lastEnvSuccesfulDeploys',
                    }
                    : undefined,
                startsWithArtifact: '$startsWithArtifact',
                masterOnly: '$masterOnly',
                stagesToHighlight: projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.releasePipelines.stagesToHighlight.map(stage => ({
                    name: stage,
                    exists: `$${stage}:exists`,
                    used: `$${stage}:used`,
                })),
                ignoredStagesBefore: projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.releasePipelines.ignoreStagesBefore,
            },
        },
    ];
};
const addBooleanFields = (collectionName, project) => {
    const projectConfig = configForProject(collectionName, project);
    const lastEnvironmentName = (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.environments)
        ? last(projectConfig.environments)
        : undefined;
    const lastEnvironmentFields = lastEnvironmentName
        ? {
            deployedToLastEnvironment: isStageUsed(lastEnvironmentName),
            successfulDeployToLastEnvironment: isStageSuccessful(lastEnvironmentName),
        }
        : {};
    return {
        $addFields: {
            startsWithArtifact: forAllArtifacts({
                $in: ['$$artifact.type', ['Build', 'Artifactory']],
            }),
            masterOnly: forAllArtifacts({
                $and: [
                    { $eq: ['$$artifact.type', 'Build'] },
                    {
                        $or: [
                            { $eq: ['$$artifact.definition.branch', 'refs/heads/master'] },
                            { $eq: ['$$artifact.definition.branch', 'refs/heads/main'] },
                        ],
                    },
                ],
            }),
            ...addStagesToHighlight(collectionName, project),
            ...lastEnvironmentFields,
        },
    };
};
const branchPolicyConformanceWithCount = (queryContext) => {
    const { collectionName, project } = fromContext(queryContext);
    const projectConfig = configForProject(collectionName, project);
    const ignoreStagesBefore = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.releasePipelines.ignoreStagesBefore;
    return [
        ...addFilteredEnvsField(ignoreStagesBefore),
        addHasGoneAhead,
        { $match: { hasGoneAhead: true } },
        { $unwind: '$artifacts' },
        { $match: { 'artifacts.type': 'Build' } },
        {
            $group: {
                _id: {
                    collectionName: '$collectionName',
                    project: '$project',
                    repositoryId: '$artifacts.definition.repositoryId',
                    branch: '$artifacts.definition.branch',
                },
                count: { $sum: 1 },
            },
        },
        {
            $project: {
                collectionName: '$_id.collectionName',
                project: '$_id.project',
                repositoryId: '$_id.repositoryId',
                branch: '$_id.branch',
                count: '$count',
            },
        },
        {
            $lookup: {
                from: 'combinedbranchpolicies',
                let: {
                    collectionName: '$collectionName',
                    project: '$project',
                    repositoryId: '$repositoryId',
                    branch: '$branch',
                },
                pipeline: [
                    {
                        $match: {
                            $expr: {
                                $and: [
                                    { $eq: ['$collectionName', '$$collectionName'] },
                                    { $eq: ['$project', '$$project'] },
                                    { $eq: ['$repositoryId', '$$repositoryId'] },
                                    { $eq: ['$refName', '$$branch'] },
                                ],
                            },
                        },
                    },
                ],
                as: 'conforms',
            },
        },
        { $project: { conforms: { $arrayElemAt: ['$conforms', 0] }, count: '$count' } },
        {
            $project: { conforms: { $ifNull: ['$conforms.conforms', false] }, count: '$count' },
        },
        {
            $project: {
                _id: 0,
                repositoryId: '$_id.repositoryId',
                branch: '$_id.branch',
                conforms: '$conforms',
                count: '$count',
            },
        },
    ];
};
export const getReposConformingToBranchPolicies = async (queryContext, repoIds) => {
    const { collectionName, project, startDate, endDate } = fromContext(queryContext);
    const result = await ReleaseModel.aggregate([
        {
            $match: {
                collectionName,
                project,
                'modifiedOn': inDateRange(startDate, endDate),
                'artifacts.definition.repositoryId': { $in: repoIds },
            },
        },
        ...branchPolicyConformanceWithCount(queryContext),
        { $match: { repositoryId: { $in: repoIds } } },
        {
            $group: {
                _id: { repositoryId: '$repositoryId', conforms: '$conforms' },
                branch: { $addToSet: '$branch' },
            },
        },
        {
            $group: {
                _id: '$_id.repositoryId',
                conforming: {
                    $sum: { $cond: [{ $eq: ['$_id.conforms', true] }, { $size: '$branch' }, 0] },
                },
                notConforming: {
                    $sum: { $cond: [{ $eq: ['$_id.conforms', false] }, { $size: '$branch' }, 0] },
                },
            },
        },
        {
            $group: {
                _id: null,
                repoCount: { $sum: 1 },
                conformingRepos: { $sum: { $cond: [{ $gt: ['$notConforming', 0] }, 0, 1] } },
                conformingBranches: { $sum: '$conforming' },
                totalBranches: { $sum: { $add: ['$conforming', '$notConforming'] } },
            },
        },
    ]);
    const first = head(result);
    if (!first)
        return null;
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    const { _id, ...rest } = first;
    return rest;
};
export const conformsToBranchPoliciesSummary = async (options) => {
    var _a;
    const filter = await createFilter(options);
    const result = await ReleaseModel.aggregate([
        ...filter,
        ...branchPolicyConformanceWithCount(options.queryContext),
        { $group: { _id: '$conforms', count: { $sum: '$count' } } },
    ]);
    return {
        conforms: ((_a = result.find(x => x._id)) === null || _a === void 0 ? void 0 : _a.count) || 0,
        total: sum(result.map(x => x.count)),
    };
};
export const getReleasesSummaryForSse = async (options) => {
    const { collectionName, project } = fromContext(options.queryContext);
    const filter = await createFilter(options);
    const [summary] = await ReleaseModel.aggregate([
        ...filter,
        addBooleanFields(collectionName, project),
        ...createSummary(collectionName, project),
    ]);
    return { ...omit(['_id'], summary) };
};
export const summary = async (options) => {
    const { collectionName, project } = fromContext(options.queryContext);
    const filter = await createFilter(options);
    const [[summary], branchPolicy] = await Promise.all([
        ReleaseModel.aggregate([
            ...filter,
            addBooleanFields(collectionName, project),
            ...createSummary(collectionName, project),
        ]),
        conformsToBranchPoliciesSummary(options),
    ]);
    return {
        ...omit(['_id'], summary),
        branchPolicy,
    };
};
export const paginatedReleaseIdsInputParser = z.object({
    ...pipelineFiltersInput,
    cursor: z
        .object({
        pageSize: z.number().optional(),
        pageNumber: z.number().optional(),
    })
        .nullish(),
});
export const filteredReleaseCount = async (options) => {
    var _a;
    const filter = await createFilter(options);
    const result = await ReleaseModel.aggregate([
        ...filter,
        {
            $group: {
                _id: '$releaseDefinitionId',
                releaseDefinitionUrl: { $first: '$releaseDefinitionUrl' },
                releaseDefinitionName: { $first: '$releaseDefinitionName' },
                lastModifiedOn: { $max: '$modifiedOn' },
            },
        },
        {
            $group: {
                _id: null,
                count: { $sum: 1 },
            },
        },
    ]);
    return ((_a = result[0]) === null || _a === void 0 ? void 0 : _a.count) || 0;
};
export const paginatedReleaseIds = async (options) => {
    var _a, _b, _c, _d, _e;
    const filter = await createFilter(options);
    const page = await ReleaseModel.aggregate([
        ...filter,
        {
            $group: {
                _id: '$releaseDefinitionId',
                releaseDefinitionUrl: { $first: '$releaseDefinitionUrl' },
                releaseDefinitionName: { $first: '$releaseDefinitionName' },
                lastModifiedOn: { $max: '$modifiedOn' },
            },
        },
        { $sort: { lastModifiedOn: -1, _id: -1 } },
        { $skip: (((_a = options.cursor) === null || _a === void 0 ? void 0 : _a.pageNumber) || 0) * (((_b = options.cursor) === null || _b === void 0 ? void 0 : _b.pageSize) || 5) },
        { $limit: ((_c = options.cursor) === null || _c === void 0 ? void 0 : _c.pageSize) || 5 },
        {
            $project: {
                url: '$releaseDefinitionUrl',
                name: '$releaseDefinitionName',
            },
        },
    ]);
    return {
        items: page.map(pipeline => ({
            id: pipeline._id,
            url: pipeline.url.replace('/_apis/Release/definitions/', '/_release?definitionId='),
            name: pipeline.name,
        })),
        nextCursor: {
            pageNumber: (((_d = options.cursor) === null || _d === void 0 ? void 0 : _d.pageNumber) || 0) + 1,
            pageSize: ((_e = options.cursor) === null || _e === void 0 ? void 0 : _e.pageSize) || 5,
        },
    };
};
export const releasePipelineDetailsInputParser = z.object({
    queryContext: queryContextInputParser,
    releaseDefnId: z.number(),
});
const releasePipelineStages = async ({ queryContext, releaseDefnId, }) => {
    const { collectionName, project, startDate, endDate } = fromContext(queryContext);
    const [releaseDefn, environments] = await Promise.all([
        ReleaseDefinitionModel.findOne({ collectionName, project, id: releaseDefnId }, { environments: 1 }).lean(),
        ReleaseModel.aggregate([
            {
                $match: {
                    collectionName,
                    project,
                    releaseDefinitionId: releaseDefnId,
                    modifiedOn: inDateRange(startDate, endDate),
                },
            },
            {
                $unwind: { path: '$environments' },
            },
            {
                $group: {
                    _id: '$environments.name',
                    runs: {
                        $sum: {
                            $cond: {
                                if: { $ne: ['$environments.status', 'notStarted'] },
                                then: 1,
                                else: 0,
                            },
                        },
                    },
                    successes: {
                        $sum: {
                            $cond: {
                                if: { $eq: ['$environments.status', 'succeeded'] },
                                then: 1,
                                else: 0,
                            },
                        },
                    },
                },
            },
        ]),
    ]);
    return releaseDefn === null || releaseDefn === void 0 ? void 0 : releaseDefn.environments.map(env => {
        const matchingEnvStats = environments.find(e => e._id === env.name);
        return {
            name: env.name,
            conditions: env.conditions.map(c => ({ type: c.conditionType, name: c.name })),
            rank: env.rank,
            total: (matchingEnvStats === null || matchingEnvStats === void 0 ? void 0 : matchingEnvStats.runs) || 0,
            successful: (matchingEnvStats === null || matchingEnvStats === void 0 ? void 0 : matchingEnvStats.successes) || 0,
        };
    });
};
const getArtifacts = async ({ queryContext, releaseDefnId, }) => {
    const { collectionName, project, startDate, endDate } = fromContext(queryContext);
    const projectConfig = configForProject(collectionName, project);
    const ignoreStagesBefore = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.releasePipelines.ignoreStagesBefore;
    const results = await ReleaseModel.aggregate([
        {
            $match: {
                collectionName,
                project,
                releaseDefinitionId: releaseDefnId,
                modifiedOn: inDateRange(startDate, endDate),
            },
        },
        ...(ignoreStagesBefore
            ? [
                ...addFilteredEnvsField(ignoreStagesBefore),
                addHasGoneAhead,
                { $unset: 'filteredEnvs' },
            ]
            : []),
        { $unwind: '$artifacts' },
        {
            $group: {
                _id: {
                    type: '$artifacts.type',
                    alias: '$artifacts.alias',
                    repositoryName: '$artifacts.definition.repositoryName',
                    repositoryId: '$artifacts.definition.repositoryId',
                    branch: '$artifacts.definition.branch',
                },
                buildPipelineUrl: { $first: '$artifacts.definition.buildPipelineUrl' },
                isPrimary: { $first: '$artifacts.isPrimary' },
                hasGoneAhead: { $push: '$hasGoneAhead' },
            },
        },
        {
            $addFields: {
                hasGoneAhead: { $anyElementTrue: '$hasGoneAhead' },
            },
        },
    ]);
    const conformsStatus = await Promise.all(results
        .map(r => {
        if (r._id.type !== 'Build')
            return;
        return { repositoryId: r._id.repositoryId, refName: r._id.branch };
    })
        .filter(exists)
        .map(async (r) => {
        return {
            ...r,
            conforms: await conformsToBranchPolicies({ collectionName, project, ...r }),
        };
    }));
    const { builds, others } = results.reduce((acc, result) => {
        var _a;
        if (result._id.type === 'Build') {
            acc.builds[result.buildPipelineUrl] = acc.builds[result.buildPipelineUrl] || {
                type: 'Build',
                name: result._id.repositoryName,
                repoId: result._id.repositoryId,
                isPrimary: result.isPrimary || undefined,
                branches: [],
                additionalBranches: [],
            };
            const branchesList = result.hasGoneAhead
                ? acc.builds[result.buildPipelineUrl].branches
                : acc.builds[result.buildPipelineUrl].additionalBranches;
            if (!branchesList.some(b => result._id.type === 'Build' && b.name === result._id.branch)) {
                branchesList.push({
                    name: result._id.branch,
                    conforms: (_a = conformsStatus.find(c => {
                        return (result._id.type === 'Build' &&
                            c.repositoryId === result._id.repositoryId &&
                            c.refName === result._id.branch);
                    })) === null || _a === void 0 ? void 0 : _a.conforms,
                });
            }
        }
        else if (!acc.others.some(artifact => artifact.type === result._id.type && artifact.alias === result._id.alias)) {
            acc.others.push({
                type: result._id.type,
                source: result._id.type,
                alias: result._id.alias,
                isPrimary: result.isPrimary || undefined,
            });
        }
        return acc;
    }, { builds: {}, others: [] });
    return [...others, ...Object.values(builds)];
};
export const releasePipelineDetails = async (args) => {
    const [stages, artifacts] = await Promise.all([
        releasePipelineStages(args),
        getArtifacts(args),
    ]);
    return { stages, artifacts };
};
export const releaseBranchesForRepo = async (queryContext, repositoryId) => {
    const { collectionName, project, startDate, endDate } = fromContext(queryContext);
    const projectConfig = configForProject(collectionName, project);
    const ignoreStagesBefore = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.releasePipelines.ignoreStagesBefore;
    const results = await ReleaseModel.aggregate([
        {
            $match: {
                collectionName,
                project,
                'artifacts.definition.repositoryId': repositoryId,
                'modifiedOn': inDateRange(startDate, endDate),
            },
        },
        ...(ignoreStagesBefore
            ? [
                ...addFilteredEnvsField(ignoreStagesBefore),
                addHasGoneAhead,
                { $unset: 'filteredEnvs' },
            ]
            : []),
        { $match: { hasGoneAhead: true } },
        { $unwind: '$artifacts' },
        { $match: { 'artifacts.definition.repositoryId': repositoryId } },
        { $project: { branch: '$artifacts.definition.branch' } },
        { $group: { _id: '$branch' } },
    ]);
    return Promise.all(results
        .map(r => r._id)
        .map(async (refName) => {
        return {
            name: refName,
            conforms: await conformsToBranchPolicies({
                collectionName,
                project,
                repositoryId,
                refName,
            }),
        };
    }));
};
export const usageByEnvironment = async (options) => {
    var _a, _b, _c;
    const filter = await createFilter(options);
    const { collectionName, project } = fromContext(options.queryContext);
    const projectConfig = configForProject(collectionName, project);
    const result = await ReleaseModel.aggregate([
        ...filter,
        {
            $addFields: 
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            ((_a = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.environments) === null || _a === void 0 ? void 0 : _a.reduce((acc, env) => {
                acc[`${env}:used`] = isStageUsed(env);
                acc[`${env}:successful`] = isStageSuccessful(env);
                return acc;
            }, {})) || {},
        },
        {
            $group: {
                _id: null,
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                ...(_b = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.environments) === null || _b === void 0 ? void 0 : _b.reduce((acc, env) => {
                    acc[`${env}:used`] = incIfTrue(`$${env}:used`);
                    acc[`${env}:successful`] = incIfTrue(`$${env}:successful`);
                    return acc;
                }, {}),
            },
        },
    ]);
    if (!result[0])
        return;
    return (_c = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.environments) === null || _c === void 0 ? void 0 : _c.reduce((acc, env) => {
        acc[env] = {
            successful: result[0][`${env}:successful`],
            total: result[0][`${env}:used`],
        };
        return acc;
    }, {});
};
export const getHasReleasesSummary = async (queryContext, repoIds) => {
    const { collectionName, project, startDate, endDate } = fromContext(queryContext);
    const result = await ReleaseModel.distinct('artifacts.definition.repositoryId', {
        collectionName,
        project,
        'modifiedOn': inDateRange(startDate, endDate),
        'artifacts.type': 'Build',
    });
    const hasReleasesRepos = repoIds.filter(repoId => result.includes(repoId));
    return hasReleasesRepos.length;
};
export const getReleasePipelinesSummaryAsChunks = async (options, onChunk) => {
    const sendChunk = (key) => (data) => {
        onChunk({ [key]: data });
    };
    await Promise.all([
        getReleasesSummaryForSse(options).then(sendChunk('releases')),
        conformsToBranchPoliciesSummary(options).then(sendChunk('releasesBranchPolicy')),
        usageByEnvironment(options).then(sendChunk('usageByEnv')),
    ]);
};
export const getReleasePipelinesSummary = async (options) => {
    let mergedChunks = {};
    await getReleasePipelinesSummaryAsChunks(options, x => {
        mergedChunks = { ...mergedChunks, ...x };
    });
    return mergedChunks;
};
