import yaml from 'yaml';
import { z } from 'zod';
import { configForProject, getConfig } from '../../config.js';
import { collectionAndProjectInputs, inDateRange } from '../helpers.js';
import { BuildModel } from '../mongoose-models/BuildModel.js';
import { fromContext } from '../utils.js';
import { getActivePipelineIds } from '../build-definitions.js';
import { getDefaultBranchAndNameForRepoIds } from '../repos.js';
import { normalizeBranchName } from '../../utils.js';
import { processSpecmaticData, processSpecmaticCentralRepoReport } from './specmatic.js';
import { AzureBuildReportModel } from './AzureBuildReportModel.js';
const templateRepo = (buildScript) => {
    var _a, _b;
    if (!buildScript)
        return;
    const parsed = yaml.parse(buildScript);
    const possibleTemplate = parsed.template ||
        (
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        (_b = (_a = parsed.stages) === null || _a === void 0 ? void 0 : _a.find((s) => s.template)) === null || _b === void 0 ? void 0 : _b.template);
    if (!possibleTemplate)
        return;
    const parts = possibleTemplate.split('@');
    if (parts.length > 1)
        return parts[1];
    return possibleTemplate;
};
export const saveBuildReport = (report) => AzureBuildReportModel.updateOne({
    collectionName: report.collectionName,
    project: report.project,
    buildId: report.buildId,
}, {
    $set: {
        repo: report.repo,
        repoId: report.repoId,
        repoUrl: report.repoUrl,
        branch: report.branch,
        branchName: report.branchName,
        buildDefinitionId: report.buildDefinitionId,
        buildReason: report.buildReason,
        buildScript: report.buildScript,
        agentName: report.agentName,
        ...(report.buildScript
            ? {
                templateRepo: templateRepo(report.buildScript),
            }
            : {}),
        ...(report.sonarHost
            ? {
                sonarHost: report.sonarHost,
                sonarProjectKey: report.sonarProjectKey,
            }
            : {}),
        centralTemplate: report.centralTemplate,
        ...processSpecmaticData(report),
        ...processSpecmaticCentralRepoReport(report),
    },
}, { upsert: true });
export const latestBuildReportsForRepo = (collectionName, project) => (repo) => AzureBuildReportModel.aggregate([
    {
        $match: {
            collectionName,
            project,
            repo,
        },
    },
    {
        $group: {
            _id: '$buildDefinitionId',
            buildReports: {
                $max: { $mergeObjects: [{ updatedAt: '$updatedAt' }, '$$ROOT'] },
            },
        },
    },
    { $replaceRoot: { newRoot: '$buildReports' } },
]);
export const centralBuildTemplateBuildCount = (collectionName, project) => async (buildDefinitionId, queryFrom = getConfig().azure.queryFrom) => {
    var _a, _b;
    const projectConfig = configForProject(collectionName, project);
    const result = await AzureBuildReportModel.aggregate([
        {
            $match: {
                collectionName,
                project,
                buildDefinitionId,
                createdAt: { $gt: queryFrom },
            },
        },
        {
            $project: {
                usesCentralTemplate: {
                    $or: [
                        { $eq: ['$centralTemplate', true] },
                        { $eq: [{ $type: '$centralTemplate' }, 'object'] },
                        (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.templateRepoName)
                            ? { $eq: ['$templateRepo', projectConfig.templateRepoName] }
                            : {},
                    ],
                },
            },
        },
        { $match: { usesCentralTemplate: true } },
        { $count: 'centralTemplateUsageCount' },
    ]);
    return (_b = (_a = result[0]) === null || _a === void 0 ? void 0 : _a.centralTemplateUsageCount) !== null && _b !== void 0 ? _b : 0;
};
export const centralTemplateOptionsInputParser = z.object({
    ...collectionAndProjectInputs,
    buildDefinitionId: z.string(),
});
export const centralTemplateOptions = async ({ collectionName, project, buildDefinitionId, }) => {
    const result = await AzureBuildReportModel.aggregate([
        {
            $match: {
                collectionName,
                project,
                buildDefinitionId,
            },
        },
        {
            $addFields: {
                hasCentralTemplateData: {
                    $or: [
                        { $eq: ['$centralTemplate', true] },
                        { $eq: [{ $type: '$centralTemplate' }, 'object'] },
                    ],
                },
            },
        },
        { $sort: { createdAt: -1 } },
        { $limit: 1 },
        { $project: { centralTemplate: 1 } },
    ]);
    if (!result.length)
        return null;
    return Object.fromEntries(Object.entries(result[0].centralTemplate).map(([key, value]) => [
        key.trim().replaceAll('_', ' '),
        value.trim() === 'true' ? true : value.trim() === 'false' ? false : value.trim(),
    ]));
};
export const buildsCentralTemplateStats = async (queryContext, repositoryId) => {
    const { collectionName, project, startDate, endDate } = fromContext(queryContext);
    const repo = await getDefaultBranchAndNameForRepoIds(queryContext, [repositoryId]).then(results => results[0]);
    if (!repo)
        return null;
    return AzureBuildReportModel.aggregate([
        {
            $match: {
                collectionName,
                project,
                repo: repo.name,
                createdAt: { $gte: new Date(startDate), $lt: new Date(endDate) },
            },
        },
        {
            $addFields: {
                usesCentralTemplate: {
                    $or: [
                        { $eq: ['$centralTemplate', true] },
                        { $eq: [{ $type: '$centralTemplate' }, 'object'] },
                        { $eq: ['$templateRepo', 'build-pipeline-templates'] },
                    ],
                },
            },
        },
        {
            $group: {
                _id: {
                    collectionName: '$collectionName',
                    project: '$project',
                    repo: '$repo',
                    buildDefinitionId: '$buildDefinitionId',
                },
                templateUsers: {
                    $sum: {
                        $cond: {
                            if: { $eq: ['$usesCentralTemplate', true] },
                            then: 1,
                            else: 0,
                        },
                    },
                },
                mainBranchCentralTemplateBuilds: {
                    $sum: {
                        $cond: {
                            if: {
                                $and: [
                                    { $eq: ['$usesCentralTemplate', true] },
                                    {
                                        $eq: [
                                            '$branchName',
                                            repo.defaultBranch
                                                ? normalizeBranchName(repo.defaultBranch)
                                                : undefined,
                                        ],
                                    },
                                ],
                            },
                            then: 1,
                            else: 0,
                        },
                    },
                },
                totalAzureBuilds: { $sum: 1 },
            },
        },
        {
            $project: {
                _id: 0,
                buildDefinitionId: '$_id.buildDefinitionId',
                templateUsers: 1,
                totalAzureBuilds: 1,
                mainBranchCentralTemplateBuilds: 1,
            },
        },
    ]).exec();
};
export const getTotalCentralTemplateUsage = async (queryContext, repoNames) => {
    const { collectionName, project, startDate, endDate } = fromContext(queryContext);
    const centralTempBuildDefIDs = await AzureBuildReportModel.aggregate([
        {
            $match: {
                collectionName,
                project,
                ...(repoNames ? { repo: { $in: repoNames } } : {}),
            },
        },
        {
            $addFields: {
                usesCentralTemplate: {
                    $or: [
                        { $eq: ['$centralTemplate', true] },
                        { $eq: [{ $type: '$centralTemplate' }, 'object'] },
                        { $eq: ['$templateRepo', 'build-pipeline-templates'] },
                    ],
                },
            },
        },
        { $match: { usesCentralTemplate: true } },
        {
            $project: {
                _id: 0,
                buildId: 1,
            },
        },
    ]);
    if ((centralTempBuildDefIDs === null || centralTempBuildDefIDs === void 0 ? void 0 : centralTempBuildDefIDs.length) === 0)
        return { templateUsers: 0 };
    const count = await BuildModel.find({
        collectionName,
        project,
        id: { $in: centralTempBuildDefIDs.map(r => r.buildId) },
        finishTime: inDateRange(startDate, endDate),
    })
        .countDocuments()
        .exec();
    return { templateUsers: count };
};
export const getCentralTemplateBuildDefs = async (queryContext, repoNames) => {
    const { collectionName, project, startDate, endDate } = fromContext(queryContext);
    return AzureBuildReportModel.aggregate([
        {
            $match: {
                collectionName,
                project,
                repo: { $in: repoNames },
                createdAt: inDateRange(startDate, endDate),
            },
        },
        {
            $addFields: {
                usesCentralTemplate: {
                    $or: [
                        { $eq: ['$centralTemplate', true] },
                        { $eq: [{ $type: '$centralTemplate' }, 'object'] },
                        { $eq: ['$templateRepo', 'build-pipeline-templates'] },
                    ],
                },
            },
        },
        {
            $group: {
                _id: '$buildDefinitionId',
                buildDefinitionId: { $first: '$buildDefinitionId' },
                collectionName: { $first: '$collectionName' },
                project: { $first: '$project' },
                totalBuilds: { $sum: 1 },
                centralTemplateBuilds: {
                    $sum: {
                        $cond: [{ $eq: ['$usesCentralTemplate', true] }, 1, 0],
                    },
                },
            },
        },
        {
            $addFields: {
                buildDefinitionId: { $toInt: '$_id' },
            },
        },
        {
            $match: {
                centralTemplateBuilds: {
                    $gt: 0,
                },
            },
        },
    ]).exec();
};
export const getActivePipelineCentralTemplateBuilds = async (queryContext, repoNames, repoIds) => {
    const { collectionName, project, startDate, endDate } = fromContext(queryContext);
    const activePipelines = await getActivePipelineIds(queryContext, repoIds);
    const centralTempBuildIds = await AzureBuildReportModel.aggregate([
        {
            $match: {
                collectionName,
                project,
                repo: { $in: repoNames },
                buildDefinitionId: { $in: activePipelines.map(String) },
            },
        },
        {
            $addFields: {
                usesCentralTemplate: {
                    $or: [
                        { $eq: ['$centralTemplate', true] },
                        { $eq: [{ $type: '$centralTemplate' }, 'object'] },
                        { $eq: ['$templateRepo', 'build-pipeline-templates'] },
                    ],
                },
            },
        },
        { $match: { usesCentralTemplate: true } },
        {
            $project: {
                _id: 0,
                buildId: 1,
            },
        },
    ]);
    if ((centralTempBuildIds === null || centralTempBuildIds === void 0 ? void 0 : centralTempBuildIds.length) === 0)
        return { count: 0 };
    const count = await BuildModel.find({
        collectionName,
        project,
        id: { $in: centralTempBuildIds.map(r => Number(r.buildId)) },
        ...(activePipelines && activePipelines.length > 0
            ? { 'definition.id': { $in: activePipelines } }
            : {}),
        finishTime: inDateRange(startDate, endDate),
    })
        .countDocuments()
        .exec();
    return { count } || { count: 0 };
};
