import { z } from 'zod';
import { collectionAndProjectInputs } from './helpers.js';
import { oneFortnightInMs } from '../../shared/utils.js';
import { repoDefaultBranch } from './repos.js';
import { BranchModel } from './mongoose-models/BranchModel.js';
import { fromContext } from './utils.js';
export const branchStatsForRepo = (collectionName, project) => async (repositoryId) => {
    const result = await BranchModel.find({
        collectionName,
        project,
        repositoryId,
    }).lean();
    return result || [];
};
export const getHealthyBranchesSummary = async (queryContext, repoIds, defaultBranchIDs) => {
    const { collectionName, project } = fromContext(queryContext);
    const today = new Date();
    const fifteenDaysBack = new Date(today.getTime() - oneFortnightInMs);
    const result = await BranchModel.aggregate([
        {
            $match: {
                collectionName,
                project,
                repositoryId: { $in: repoIds },
            },
        },
        {
            $group: {
                _id: { collectionName: '$collectionName', project: '$project' },
                total: { $sum: 1 },
                healthy: {
                    $sum: {
                        $cond: [
                            {
                                $or: [
                                    {
                                        $and: [
                                            { $lt: ['$aheadCount', 10] },
                                            { $lt: ['$behindCount', 10] },
                                            { $gte: ['$date', fifteenDaysBack] },
                                        ],
                                    },
                                    { $in: ['$_id', defaultBranchIDs] },
                                ],
                            },
                            1,
                            0,
                        ],
                    },
                },
            },
        },
        {
            $project: {
                _id: 0,
                total: 1,
                healthy: 1,
            },
        },
    ]);
    return result[0] || { total: 0, healthy: 0 };
};
export const categoryAddFields = (startDate, defaultBranch) => {
    return {
        $switch: {
            branches: [
                {
                    case: {
                        $or: [
                            {
                                $and: [
                                    { $lt: ['$aheadCount', 10] },
                                    { $lt: ['$behindCount', 10] },
                                    { $gte: ['$date', startDate] },
                                ],
                            },
                            { $eq: ['$name', defaultBranch] },
                        ],
                    },
                    then: 'healthy',
                },
                {
                    case: {
                        $and: [
                            { $ne: ['$category', 'healthy'] },
                            { $eq: ['$aheadCount', 0] },
                            { $lt: ['$date', startDate] },
                            { $ne: ['$name', defaultBranch] },
                        ],
                    },
                    then: 'delete',
                },
                {
                    case: {
                        $and: [
                            { $ne: ['$category', 'healthy'] },
                            { $gt: ['$aheadCount', 0] },
                            { $lt: ['$date', startDate] },
                        ],
                    },
                    then: 'abandoned',
                },
            ],
            default: 'unhealthy',
        },
    };
};
export const RepoTotalBranchesInputParser = z.object({
    ...collectionAndProjectInputs,
    repositoryId: z.string(),
});
export const getRepoBranchStats = async ({ collectionName, project, repositoryId, }) => {
    const today = new Date();
    const fifteenDaysBack = new Date(today.getTime() - oneFortnightInMs);
    const defaultBranch = await repoDefaultBranch(collectionName, project, repositoryId);
    if (!defaultBranch)
        return;
    const result = await BranchModel.aggregate([
        { $match: { collectionName, project, repositoryId } },
        {
            $addFields: {
                category: categoryAddFields(fifteenDaysBack, defaultBranch),
            },
        },
        {
            $group: {
                _id: null,
                totalBranches: { $sum: 1 },
                totalHealthy: {
                    $sum: { $cond: [{ $eq: ['$category', 'healthy'] }, 1, 0] },
                },
                totalDelete: {
                    $sum: { $cond: [{ $eq: ['$category', 'delete'] }, 1, 0] },
                },
                totalAbandoned: {
                    $sum: { $cond: [{ $eq: ['$category', 'abandoned'] }, 1, 0] },
                },
                totalUnhealthy: {
                    $sum: { $cond: [{ $eq: ['$category', 'unhealthy'] }, 1, 0] },
                },
            },
        },
        {
            $project: {
                _id: 0,
                totalBranches: 1,
                totalHealthy: 1,
                totalDelete: 1,
                totalAbandoned: 1,
                totalUnhealthy: 1,
            },
        },
    ]);
    return result[0];
};
export const getTotalBranchesForRepositoryIds = async (queryContext, repositoryIds) => {
    const { collectionName, project } = fromContext(queryContext);
    return BranchModel.aggregate([
        {
            $match: {
                collectionName,
                project,
                repositoryId: { $in: repositoryIds },
            },
        },
        {
            $group: {
                _id: '$repositoryId',
                total: { $sum: 1 },
            },
        },
        {
            $project: {
                _id: 0,
                repositoryId: '$_id',
                total: 1,
            },
        },
    ]);
};
const setBranchUrl = (branchName, repoUrl, linkType) => {
    return `${repoUrl}/?_a=${linkType}&version=GB${encodeURIComponent(branchName)}`;
};
export const BranchesListInputParser = z.object({
    ...collectionAndProjectInputs,
    repositoryId: z.string(),
    repoUrl: z.string(),
    limit: z.number(),
});
export const getBranches = (category, linkType) => async ({ collectionName, project, repositoryId, repoUrl, limit, }) => {
    const today = new Date();
    const fifteenDaysBack = new Date(today.getTime() - oneFortnightInMs);
    const defaultBranch = await repoDefaultBranch(collectionName, project, repositoryId);
    if (!defaultBranch)
        return;
    const result = await BranchModel.aggregate([
        { $match: { collectionName, project, repositoryId } },
        {
            $addFields: {
                category: categoryAddFields(fifteenDaysBack, defaultBranch),
            },
        },
        {
            $match: {
                category,
            },
        },
        {
            $project: {
                _id: 0,
                aheadCount: 1,
                behindCount: 1,
                lastCommitDate: '$date',
                name: 1,
            },
        },
        { $limit: limit },
        {
            $sort: category === 'healthy'
                ? { lastCommitDate: -1 }
                : category === 'abandoned'
                    ? { aheadCount: -1 }
                    : { lastCommitDate: 1 },
        },
    ]);
    const withUrls = result.map(branch => {
        return {
            ...branch,
            url: setBranchUrl(encodeURIComponent(branch.name), repoUrl, linkType),
        };
    });
    return {
        branches: withUrls || [],
        count: withUrls.length || 0,
        limit,
    };
};
export const getHealthyBranchesList = getBranches('healthy', 'contents');
export const getDeleteCandidateBranchesList = getBranches('delete', 'history');
export const getAbandonedBranchesList = getBranches('abandoned', 'history');
export const getUnhealthyBranchesList = getBranches('unhealthy', 'history');
