import { WrappedData } from './types.js'; export interface QuizQuestion { id: number; question: string; options: string[]; correctIndex: number; explanation: string; emoji: string; category: 'team' | 'time' | 'fun' | 'guess'; } export class TeamQuizGenerator { private questions: QuizQuestion[] = []; private dayTranslations: Record = { 'Monday': 'Lundi', 'Tuesday': 'Mardi', 'Wednesday': 'Mercredi', 'Thursday': 'Jeudi', 'Friday': 'Vendredi', 'Saturday': 'Samedi', 'Sunday': 'Dimanche' }; constructor(private data: WrappedData) { this.generateAllQuestions(); } private translateDay(day: string): string { return this.dayTranslations[day] || day; } private generateAllQuestions(): void { this.questions = [ ...this.generateTeamQuestions(), ...this.generateTimeQuestions(), ...this.generateFunQuestions(), ...this.generateGuessQuestions() ]; // Shuffle questions this.questions = this.shuffleArray(this.questions); // Re-assign IDs after shuffle this.questions.forEach((q, i) => q.id = i + 1); } private shuffleArray(array: T[]): T[] { const shuffled = [...array]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; } return shuffled; } private generateTeamQuestions(): QuizQuestion[] { const questions: QuizQuestion[] = []; // Question: Total team commits const totalCommits = this.data.teamSummary.totalCommits; const commitOptions = [ totalCommits, Math.round(totalCommits * 0.7), Math.round(totalCommits * 1.3), Math.round(totalCommits * 0.5) ].map(n => n.toLocaleString()); questions.push({ id: 0, question: "Combien de commits l'équipe a-t-elle fait au total ?", options: this.shuffleArray(commitOptions), correctIndex: 0, explanation: `L'équipe a fait exactement ${totalCommits.toLocaleString()} commits !`, emoji: '📊', category: 'team' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(totalCommits.toLocaleString()); // Question: Total lines added const totalLinesAdded = this.data.teamSummary.linesAdded; const linesOptions = [ totalLinesAdded, Math.round(totalLinesAdded * 0.6), Math.round(totalLinesAdded * 1.4), Math.round(totalLinesAdded * 0.8) ].map(n => n.toLocaleString()); questions.push({ id: 0, question: "Combien de lignes de code l'équipe a-t-elle ajoutées ?", options: this.shuffleArray(linesOptions), correctIndex: 0, explanation: `${totalLinesAdded.toLocaleString()} lignes ajoutées ! C'est beaucoup de code !`, emoji: '📝', category: 'team' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(totalLinesAdded.toLocaleString()); // Question: Total PRs merged if (this.data.pullRequests) { const totalPRs = this.data.pullRequests.totalPRs.merged; const prOptions = [totalPRs, totalPRs + 100, totalPRs - 150, Math.round(totalPRs * 1.5)] .filter(n => n > 0) .map(n => n.toString()); questions.push({ id: 0, question: "Combien de Pull Requests ont été mergées au total ?", options: this.shuffleArray(prOptions), correctIndex: 0, explanation: `${totalPRs} PRs mergées cette année ! Belle collaboration !`, emoji: '✅', category: 'team' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(totalPRs.toString()); } // Question: Average commits per day const avgCommitsPerDay = (totalCommits / 365).toFixed(1); const avgOptions = [ avgCommitsPerDay, (parseFloat(avgCommitsPerDay) * 0.5).toFixed(1), (parseFloat(avgCommitsPerDay) * 1.5).toFixed(1), (parseFloat(avgCommitsPerDay) * 2).toFixed(1) ]; questions.push({ id: 0, question: "En moyenne, combien de commits par jour l'équipe fait-elle ?", options: this.shuffleArray(avgOptions), correctIndex: 0, explanation: `${avgCommitsPerDay} commits par jour en moyenne !`, emoji: '📈', category: 'team' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(avgCommitsPerDay); return questions; } private generateTimeQuestions(): QuizQuestion[] { const questions: QuizQuestion[] = []; // Question: Favorite day of the week (translated to French) const dayData = this.data.commitsByDayOfWeek || {}; const sortedDays = Object.entries(dayData).sort((a, b) => b[1] - a[1]); if (sortedDays.length > 0) { const topDay = sortedDays[0][0]; const topDayFr = this.translateDay(topDay); const otherDays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'] .filter(d => d !== topDay) .slice(0, 3) .map(d => this.translateDay(d)); questions.push({ id: 0, question: "Quel est le jour préféré de l'équipe pour coder ?", options: this.shuffleArray([topDayFr, ...otherDays]), correctIndex: 0, explanation: `${topDayFr} avec ${sortedDays[0][1]} commits!`, emoji: '📅', category: 'time' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(topDayFr); } // Question: Busiest month const busiestMonth = this.data.busiestMonths[0]; if (busiestMonth) { const monthDate = new Date(busiestMonth.month + '-01'); const monthName = monthDate.toLocaleDateString('fr-FR', { month: 'long', year: 'numeric' }); const otherMonths = this.data.busiestMonths.slice(1, 4).map(m => { const d = new Date(m.month + '-01'); return d.toLocaleDateString('fr-FR', { month: 'long', year: 'numeric' }); }); questions.push({ id: 0, question: "Quel a été le mois le plus productif ?", options: this.shuffleArray([monthName, ...otherMonths]), correctIndex: 0, explanation: `${monthName} avec ${busiestMonth.commits} commits !`, emoji: '🗓️', category: 'time' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(monthName); } // Question: Night owl commits (team total) const nightOwlTotal = Object.values(this.data.nightOwlCommits).reduce((a, b) => a + b, 0); const nightOptions = [nightOwlTotal, nightOwlTotal + 20, Math.max(1, nightOwlTotal - 8), nightOwlTotal * 2] .filter(n => n > 0) .map(n => n.toString()); questions.push({ id: 0, question: "Combien de commits ont été faits après 22h ? (Night owls!)", options: this.shuffleArray(nightOptions), correctIndex: 0, explanation: `${nightOwlTotal} commits nocturnes ! L'équipe a des couche-tard !`, emoji: '🦉', category: 'time' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(nightOwlTotal.toString()); // Question: Early bird commits (team total) const earlyBirdTotal = Object.values(this.data.earlyBirdCommits || {}).reduce((a, b) => a + b, 0); if (earlyBirdTotal > 0) { const earlyOptions = [earlyBirdTotal, earlyBirdTotal + 15, Math.max(1, earlyBirdTotal - 10), earlyBirdTotal * 2] .filter(n => n > 0) .map(n => n.toString()); questions.push({ id: 0, question: "Combien de commits ont été faits avant 9h du matin ?", options: this.shuffleArray(earlyOptions), correctIndex: 0, explanation: `${earlyBirdTotal} commits matinaux ! Des lève-tôt dans l'équipe !`, emoji: '🌅', category: 'time' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(earlyBirdTotal.toString()); } // Question: Busiest single day const busiestDays = this.data.busiestDays || []; if (busiestDays.length > 0) { const topDay = busiestDays[0]; const topDayFormatted = new Date(topDay.date).toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' }); const otherDays = busiestDays.slice(1, 4).map(d => new Date(d.date).toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' }) ); questions.push({ id: 0, question: "Quel jour a été le plus intense en commits ?", options: this.shuffleArray([topDayFormatted, ...otherDays]), correctIndex: 0, explanation: `Le ${topDayFormatted} avec ${topDay.commits} commits ! Journée de folie !`, emoji: '🔥', category: 'time' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(topDayFormatted); } return questions; } private generateFunQuestions(): QuizQuestion[] { const questions: QuizQuestion[] = []; // Question: Friday commits (team total) const fridayTotal = Object.values(this.data.fridayWarriorCommits || {}).reduce((a, b) => a + b, 0); if (fridayTotal > 0) { const fridayOptions = [fridayTotal, fridayTotal + 50, Math.round(fridayTotal * 0.6), Math.round(fridayTotal * 1.5)] .map(n => n.toString()); questions.push({ id: 0, question: "Combien de commits l'équipe a-t-elle fait le vendredi ? (YOLO!)", options: this.shuffleArray(fridayOptions), correctIndex: 0, explanation: `${fridayTotal} commits le vendredi ! On aime vivre dangereusement !`, emoji: '🎉', category: 'fun' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(fridayTotal.toString()); } // Question: Net lines (added - deleted) const netLines = this.data.teamSummary.netChange; const netOptions = [ netLines, Math.round(netLines * 0.5), Math.round(netLines * 2), Math.round(netLines * 1.5) ].map(n => (n >= 0 ? '+' : '') + n.toLocaleString()); questions.push({ id: 0, question: "Quel est le bilan net de lignes (ajoutées - supprimées) ?", options: this.shuffleArray(netOptions), correctIndex: 0, explanation: `${netLines >= 0 ? '+' : ''}${netLines.toLocaleString()} lignes nettes ! Le projet ${netLines >= 0 ? 'grandit' : 'se simplifie'} !`, emoji: '⚖️', category: 'fun' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf((netLines >= 0 ? '+' : '') + netLines.toLocaleString()); // Question: Lines deleted const linesDeleted = this.data.teamSummary.linesDeleted; const deletedOptions = [ linesDeleted, Math.round(linesDeleted * 0.5), Math.round(linesDeleted * 1.5), Math.round(linesDeleted * 0.7) ].map(n => n.toLocaleString()); questions.push({ id: 0, question: "Combien de lignes de code ont ete supprimees? (Le refactoring c'est bien!)", options: this.shuffleArray(deletedOptions), correctIndex: 0, explanation: `${linesDeleted.toLocaleString()} lignes supprimees! Moins de code = moins de bugs!`, emoji: '🗑️', category: 'fun' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(linesDeleted.toLocaleString()); return questions; } private generateGuessQuestions(): QuizQuestion[] { const questions: QuizQuestion[] = []; // Question: Guess the percentage of commits on favorite day const dayData = this.data.commitsByDayOfWeek || {}; const totalDayCommits = Object.values(dayData).reduce((a, b) => a + b, 0); const sortedDays = Object.entries(dayData).sort((a, b) => b[1] - a[1]); if (sortedDays.length > 0 && totalDayCommits > 0) { const topDayPercentage = Math.round((sortedDays[0][1] / totalDayCommits) * 100); const topDayFr = this.translateDay(sortedDays[0][0]); const percentOptions = [ topDayPercentage, Math.max(5, topDayPercentage - 10), Math.min(50, topDayPercentage + 10), Math.max(5, topDayPercentage - 5) ].map(n => n + '%'); questions.push({ id: 0, question: `Quel pourcentage des commits sont faits le ${topDayFr}?`, options: this.shuffleArray(percentOptions), correctIndex: 0, explanation: `${topDayPercentage}% des commits sont faits le ${topDayFr}!`, emoji: '🎯', category: 'guess' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(topDayPercentage + '%'); } // Question: Ratio PRs opened vs merged if (this.data.pullRequests) { const opened = this.data.pullRequests.totalPRs.opened; const merged = this.data.pullRequests.totalPRs.merged; const mergeRate = Math.round((merged / opened) * 100); const rateOptions = [ mergeRate, Math.max(50, mergeRate - 15), Math.min(99, mergeRate + 10), Math.max(60, mergeRate - 8) ].map(n => n + '%'); questions.push({ id: 0, question: "Quel est le taux de PRs mergees par rapport aux PRs ouvertes?", options: this.shuffleArray(rateOptions), correctIndex: 0, explanation: `${mergeRate}% des PRs ouvertes ont ete mergees!`, emoji: '🔀', category: 'guess' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(mergeRate + '%'); } // Question: How many commits in the busiest month vs average if (this.data.busiestMonths.length > 0) { const busiestMonth = this.data.busiestMonths[0]; const avgMonthlyCommits = Math.round(this.data.teamSummary.totalCommits / 12); const ratio = (busiestMonth.commits / avgMonthlyCommits).toFixed(1); const ratioOptions = [ ratio + 'x', (parseFloat(ratio) * 0.5).toFixed(1) + 'x', (parseFloat(ratio) * 1.5).toFixed(1) + 'x', (parseFloat(ratio) + 1).toFixed(1) + 'x' ]; questions.push({ id: 0, question: "Le mois le plus actif a eu combien de fois plus de commits que la moyenne?", options: this.shuffleArray(ratioOptions), correctIndex: 0, explanation: `${ratio}x plus de commits que la moyenne mensuelle!`, emoji: '📊', category: 'guess' }); questions[questions.length - 1].correctIndex = questions[questions.length - 1].options.indexOf(ratio + 'x'); } return questions; } getQuestions(): QuizQuestion[] { return this.questions; } getQuestionCount(): number { return this.questions.length; } }