import { computeTeamInsights } from '../../../../modules/statistics-insights/usecases/insights/computeTeamInsights.usecase.js';
import { MINIMUM_REVIEWS_THRESHOLD, ABSOLUTE_BENCHMARKS, computeTeamMetrics, computeCategoryLevels, identifyStrengths, identifyWeaknesses, identifyTopPriority, computeTitle, computeOverallLevel, } from '../../../../modules/statistics-insights/usecases/insights/insightLevelComputation.service.js';
const RECENT_REVIEWS_WINDOW = 20;
export function computeInsightsWithPersistence(reviews, persistedData) {
    const currentPersistedData = persistedData ?? createEmptyPersistedData();
    const processedIds = new Set(currentPersistedData.processedReviewIds);
    const newReviews = reviews.filter((review) => !processedIds.has(review.id));
    const updatedDevelopers = updateDeveloperMetrics(currentPersistedData.developers, newReviews);
    const allProcessedIds = [
        ...currentPersistedData.processedReviewIds,
        ...newReviews.map((review) => review.id),
    ];
    const eligibleDevelopers = updatedDevelopers.filter((developer) => developer.totalReviews >= MINIMUM_REVIEWS_THRESHOLD);
    const developerInsights = computeInsightsFromPersistedMetrics(eligibleDevelopers);
    const teamInsight = computeTeamInsights(developerInsights);
    return {
        developerInsights,
        teamInsight,
        persistedData: {
            developers: updatedDevelopers,
            processedReviewIds: allProcessedIds,
            lastUpdated: new Date().toISOString(),
            aiInsights: currentPersistedData.aiInsights ?? null,
            reviewCountAtAiGeneration: currentPersistedData.reviewCountAtAiGeneration ?? 0,
        },
    };
}
function createEmptyPersistedData() {
    return {
        developers: [],
        processedReviewIds: [],
        lastUpdated: new Date().toISOString(),
        aiInsights: null,
        reviewCountAtAiGeneration: 0,
    };
}
function updateDeveloperMetrics(existingDevelopers, newReviews) {
    const developerMap = new Map();
    for (const developer of existingDevelopers) {
        developerMap.set(developer.developerName, { ...developer, recentReviews: [...developer.recentReviews] });
    }
    for (const review of newReviews) {
        if (!review.assignedBy)
            continue;
        const developerName = review.assignedBy;
        const existing = developerMap.get(developerName);
        if (existing) {
            updateExistingDeveloper(existing, review);
        }
        else {
            developerMap.set(developerName, createDeveloperFromReview(review));
        }
    }
    return Array.from(developerMap.values());
}
function updateExistingDeveloper(developer, review) {
    developer.totalReviews += 1;
    developer.totalBlocking += review.blocking;
    developer.totalWarnings += review.warnings;
    developer.totalSuggestions += (review.suggestions ?? 0);
    developer.totalDuration += review.duration;
    if (review.score !== null) {
        developer.totalScore += review.score;
        developer.scoredReviewCount += 1;
    }
    if (review.diffStats !== null && review.diffStats !== undefined) {
        developer.totalAdditions += review.diffStats.additions;
        developer.totalDeletions += review.diffStats.deletions;
        developer.diffStatsReviewCount += 1;
    }
    developer.recentReviews.push(review);
    if (developer.recentReviews.length > RECENT_REVIEWS_WINDOW) {
        developer.recentReviews = developer.recentReviews.slice(-RECENT_REVIEWS_WINDOW);
    }
}
function createDeveloperFromReview(review) {
    return {
        developerName: review.assignedBy ?? '',
        totalReviews: 1,
        totalScore: review.score ?? 0,
        scoredReviewCount: review.score !== null ? 1 : 0,
        totalBlocking: review.blocking,
        totalWarnings: review.warnings,
        totalSuggestions: review.suggestions ?? 0,
        totalDuration: review.duration,
        totalAdditions: review.diffStats?.additions ?? 0,
        totalDeletions: review.diffStats?.deletions ?? 0,
        diffStatsReviewCount: (review.diffStats !== null && review.diffStats !== undefined) ? 1 : 0,
        recentReviews: [review],
    };
}
function computeInsightsFromPersistedMetrics(developers) {
    if (developers.length === 0) {
        return [];
    }
    const reviewsByDeveloper = buildReviewsByDeveloperMap(developers);
    const isSingleDeveloper = developers.length === 1;
    const teamMetrics = isSingleDeveloper
        ? ABSOLUTE_BENCHMARKS
        : computeTeamMetrics(reviewsByDeveloper);
    const insights = [];
    for (const developer of developers) {
        const serviceMetrics = buildDeveloperMetricsFromCumulative(developer);
        const trendReviews = developer.recentReviews;
        const categoryLevels = computeCategoryLevels(trendReviews, serviceMetrics, teamMetrics);
        const strengths = identifyStrengths(categoryLevels);
        const weaknesses = identifyWeaknesses(categoryLevels);
        const topPriority = identifyTopPriority(categoryLevels);
        const title = computeTitle(categoryLevels);
        const overallLevel = computeOverallLevel(categoryLevels);
        const insightDescriptions = generateInsightDescriptions(serviceMetrics, teamMetrics, strengths, weaknesses, trendReviews, categoryLevels);
        const averageAdditions = developer.diffStatsReviewCount > 0
            ? developer.totalAdditions / developer.diffStatsReviewCount
            : 0;
        const averageDeletions = developer.diffStatsReviewCount > 0
            ? developer.totalDeletions / developer.diffStatsReviewCount
            : 0;
        insights.push({
            developerName: developer.developerName,
            title,
            overallLevel,
            categoryLevels,
            strengths,
            weaknesses,
            topPriority,
            reviewCount: developer.totalReviews,
            metrics: {
                averageScore: serviceMetrics.averageScore,
                averageBlocking: serviceMetrics.averageBlocking,
                averageWarnings: serviceMetrics.averageWarnings,
                averageDuration: serviceMetrics.averageDuration,
                totalFollowups: null,
                averageAdditions,
                averageDeletions,
                firstReviewQualityRate: computeFirstReviewQualityRate(trendReviews),
            },
            insightDescriptions,
        });
    }
    return insights;
}
function buildReviewsByDeveloperMap(developers) {
    const map = new Map();
    for (const developer of developers) {
        map.set(developer.developerName, developer.recentReviews);
    }
    return map;
}
function buildDeveloperMetricsFromCumulative(developer) {
    const averageScore = developer.scoredReviewCount > 0
        ? developer.totalScore / developer.scoredReviewCount
        : 5;
    const averageBlocking = developer.totalReviews > 0
        ? developer.totalBlocking / developer.totalReviews
        : 0;
    const averageWarnings = developer.totalReviews > 0
        ? developer.totalWarnings / developer.totalReviews
        : 0;
    const averageDuration = developer.totalReviews > 0
        ? developer.totalDuration / developer.totalReviews
        : 0;
    const averageCodeVolume = developer.diffStatsReviewCount > 0
        ? (developer.totalAdditions + developer.totalDeletions) / developer.diffStatsReviewCount
        : 0;
    const correlation = computeVolumeScoreCorrelationFromRecent(developer.recentReviews);
    return {
        averageScore,
        averageBlocking,
        averageWarnings,
        averageDuration,
        averageCodeVolume,
        codeVolumeScoreCorrelation: correlation,
    };
}
function computeVolumeScoreCorrelationFromRecent(reviews) {
    const reviewsWithBoth = reviews.filter((review) => review.score !== null &&
        review.diffStats !== null &&
        review.diffStats !== undefined);
    if (reviewsWithBoth.length < 3)
        return 0;
    const scores = reviewsWithBoth.map((review) => review.score ?? 0);
    const volumes = reviewsWithBoth.map((review) => (review.diffStats?.additions ?? 0) + (review.diffStats?.deletions ?? 0));
    const avgScore = scores.reduce((sum, value) => sum + value, 0) / scores.length;
    const avgVolume = volumes.reduce((sum, value) => sum + value, 0) / volumes.length;
    let numerator = 0;
    let denominatorScore = 0;
    let denominatorVolume = 0;
    for (let index = 0; index < reviewsWithBoth.length; index++) {
        const scoreDiff = scores[index] - avgScore;
        const volumeDiff = volumes[index] - avgVolume;
        numerator += scoreDiff * volumeDiff;
        denominatorScore += scoreDiff * scoreDiff;
        denominatorVolume += volumeDiff * volumeDiff;
    }
    const denominator = Math.sqrt(denominatorScore * denominatorVolume);
    if (denominator === 0)
        return 0;
    return numerator / denominator;
}
const QUALITY_SCORE_THRESHOLD = 7;
function computeFirstReviewQualityRate(reviews) {
    const reviewsWithScore = reviews.filter((review) => review.score !== null);
    if (reviewsWithScore.length === 0)
        return 0;
    const qualityReviews = reviewsWithScore.filter((review) => (review.score ?? 0) >= QUALITY_SCORE_THRESHOLD && review.blocking === 0);
    return qualityReviews.length / reviewsWithScore.length;
}
function computePercentDifference(value, teamAverage) {
    if (teamAverage === 0)
        return 0;
    return Math.round(((value - teamAverage) / teamAverage) * 100);
}
function formatDuration(milliseconds) {
    const totalSeconds = Math.round(milliseconds / 1000);
    const minutes = Math.floor(totalSeconds / 60);
    const seconds = totalSeconds % 60;
    if (minutes === 0)
        return `${seconds}s`;
    return `${minutes}m${seconds > 0 ? `${seconds}s` : ''}`;
}
function generateInsightDescriptions(serviceMetrics, teamMetrics, strengths, weaknesses, reviews, categoryLevels) {
    const descriptions = [];
    for (const category of strengths) {
        const isTrendBased = categoryLevels[category].level < 7 && categoryLevels[category].trend === 'improving';
        const description = isTrendBased
            ? generateTrendStrengthDescription(category, categoryLevels[category].trend)
            : generateStrengthDescription(category, serviceMetrics, teamMetrics, reviews);
        if (description !== null) {
            descriptions.push(description);
        }
    }
    for (const category of weaknesses) {
        const description = generateWeaknessDescription(category, serviceMetrics, teamMetrics, reviews);
        if (description !== null) {
            descriptions.push(description);
        }
    }
    return descriptions;
}
function generateTrendStrengthDescription(category, _trend) {
    return {
        category,
        type: 'strength',
        descriptionKey: `insight.${category}.improving`,
        params: {},
    };
}
function generateStrengthDescription(category, metrics, teamMetrics, reviews) {
    switch (category) {
        case 'quality': {
            const percent = computePercentDifference(metrics.averageScore, teamMetrics.averageScore);
            return {
                category: 'quality',
                type: 'strength',
                descriptionKey: 'insight.quality.highScore',
                params: {
                    score: Math.round(metrics.averageScore * 10) / 10,
                    teamAverage: Math.round(teamMetrics.averageScore * 10) / 10,
                    percent: Math.abs(percent),
                },
            };
        }
        case 'responsiveness': {
            const percent = computePercentDifference(teamMetrics.averageDuration, metrics.averageDuration);
            return {
                category: 'responsiveness',
                type: 'strength',
                descriptionKey: 'insight.responsiveness.fast',
                params: {
                    duration: formatDuration(metrics.averageDuration),
                    teamAverage: formatDuration(teamMetrics.averageDuration),
                    percent: Math.abs(percent),
                },
            };
        }
        case 'codeVolume':
            return {
                category: 'codeVolume',
                type: 'strength',
                descriptionKey: 'insight.codeVolume.high',
                params: { lines: Math.round(metrics.averageCodeVolume) },
            };
        case 'iteration': {
            const qualityRate = computeFirstReviewQualityRate(reviews);
            return {
                category: 'iteration',
                type: 'strength',
                descriptionKey: 'insight.iteration.good',
                params: { rate: Math.round(qualityRate * 100) },
            };
        }
    }
}
function generateWeaknessDescription(category, metrics, teamMetrics, reviews) {
    switch (category) {
        case 'quality': {
            const percent = computePercentDifference(metrics.averageBlocking, teamMetrics.averageBlocking);
            return {
                category: 'quality',
                type: 'weakness',
                descriptionKey: 'insight.quality.highBlocking',
                params: {
                    blocking: Math.round(metrics.averageBlocking * 10) / 10,
                    teamAverage: Math.round(teamMetrics.averageBlocking * 10) / 10,
                    percent: Math.abs(percent),
                },
            };
        }
        case 'responsiveness': {
            const percent = computePercentDifference(metrics.averageDuration, teamMetrics.averageDuration);
            return {
                category: 'responsiveness',
                type: 'weakness',
                descriptionKey: 'insight.responsiveness.slow',
                params: {
                    duration: formatDuration(metrics.averageDuration),
                    teamAverage: formatDuration(teamMetrics.averageDuration),
                    percent: Math.abs(percent),
                },
            };
        }
        case 'codeVolume':
            return {
                category: 'codeVolume',
                type: 'weakness',
                descriptionKey: 'insight.codeVolume.low',
                params: { lines: Math.round(metrics.averageCodeVolume) },
            };
        case 'iteration': {
            const qualityRate = computeFirstReviewQualityRate(reviews);
            return {
                category: 'iteration',
                type: 'weakness',
                descriptionKey: 'insight.iteration.poor',
                params: { rate: Math.round((1 - qualityRate) * 100) },
            };
        }
    }
}
//# sourceMappingURL=computeInsightsWithPersistence.usecase.js.map