import { OverallScoreMethod } from "@prisma/client";

export type AssessmentInputModule = {
  moduleId: string;
  moduleKey: string;
  moduleName: string;
  questionWeights: {
    questionId: string;
    maxWeight: number;
  }[];
};

export type ScoringComputationConfig = {
  overallScoreMethod: OverallScoreMethod;
  moduleWeights: Record<string, number>;
};

export type ModuleScoreSummary = {
  moduleId: string;
  moduleKey: string;
  moduleName: string;
  score: number;
  completion: number;
  answeredQuestions: number;
  totalQuestions: number;
  status: "Completado" | "En curso" | "Pendiente";
};

export type AssessmentSnapshot = {
  overallScore: number;
  moduleScores: ModuleScoreSummary[];
  answeredQuestions: number;
  totalQuestions: number;
  strongestModule: ModuleScoreSummary | null;
  weakestModule: ModuleScoreSummary | null;
};

function toPercentage(value: number) {
  return Math.round(value * 10) / 10;
}

function resolveModuleStatus(completion: number, answeredQuestions: number): ModuleScoreSummary["status"] {
  if (completion >= 100) {
    return "Completado";
  }

  if (answeredQuestions > 0) {
    return "En curso";
  }

  return "Pendiente";
}

function computeOverallScore(moduleScores: ModuleScoreSummary[], config: ScoringComputationConfig) {
  if (!moduleScores.length) {
    return 0;
  }

  if (config.overallScoreMethod === OverallScoreMethod.EQUAL_ANSWERED_MODULES) {
    const answeredModules = moduleScores.filter((moduleScore) => moduleScore.answeredQuestions > 0);

    if (!answeredModules.length) {
      return 0;
    }

    return toPercentage(answeredModules.reduce((total, moduleScore) => total + moduleScore.score, 0) / answeredModules.length);
  }

  if (config.overallScoreMethod === OverallScoreMethod.WEIGHTED_ANSWERED_MODULES) {
    const answeredModules = moduleScores.filter((moduleScore) => moduleScore.answeredQuestions > 0);

    if (!answeredModules.length) {
      return 0;
    }

    let weightedScoreTotal = 0;
    let weightTotal = 0;

    for (const moduleScore of answeredModules) {
      const weight = config.moduleWeights[moduleScore.moduleKey] ?? 1;
      const safeWeight = Number.isFinite(weight) && weight > 0 ? weight : 1;

      weightedScoreTotal += moduleScore.score * safeWeight;
      weightTotal += safeWeight;
    }

    return weightTotal > 0 ? toPercentage(weightedScoreTotal / weightTotal) : 0;
  }

  return toPercentage(moduleScores.reduce((total, moduleScore) => total + moduleScore.score, 0) / moduleScores.length);
}

export function computeAssessmentSnapshot(
  modules: AssessmentInputModule[],
  selectedWeightByQuestionId: Map<string, number>,
  config: ScoringComputationConfig,
): AssessmentSnapshot {
  const moduleScores: ModuleScoreSummary[] = modules.map((moduleRecord) => {
    const totalQuestions = moduleRecord.questionWeights.length;
    let answeredQuestions = 0;
    let selectedWeightTotal = 0;
    let maxWeightTotal = 0;

    for (const questionWeight of moduleRecord.questionWeights) {
      const selectedWeight = selectedWeightByQuestionId.get(questionWeight.questionId);

      if (selectedWeight !== undefined) {
        answeredQuestions += 1;
        selectedWeightTotal += selectedWeight;
        maxWeightTotal += questionWeight.maxWeight;
      }
    }

    const completion = totalQuestions > 0 ? toPercentage((answeredQuestions / totalQuestions) * 100) : 0;
    const score = maxWeightTotal > 0 ? toPercentage((selectedWeightTotal / maxWeightTotal) * 100) : 0;

    return {
      moduleId: moduleRecord.moduleId,
      moduleKey: moduleRecord.moduleKey,
      moduleName: moduleRecord.moduleName,
      score,
      completion,
      answeredQuestions,
      totalQuestions,
      status: resolveModuleStatus(completion, answeredQuestions),
    };
  });

  const overallScore = computeOverallScore(moduleScores, config);
  const answeredQuestions = moduleScores.reduce((total, moduleScore) => total + moduleScore.answeredQuestions, 0);
  const totalQuestions = moduleScores.reduce((total, moduleScore) => total + moduleScore.totalQuestions, 0);

  const scoredModules = moduleScores.filter((moduleScore) => moduleScore.totalQuestions > 0);
  const strongestModule = scoredModules.length
    ? [...scoredModules].sort((a, b) => b.score - a.score)[0]
    : null;
  const weakestModule = scoredModules.length
    ? [...scoredModules].sort((a, b) => a.score - b.score)[0]
    : null;

  return {
    overallScore,
    moduleScores,
    answeredQuestions,
    totalQuestions,
    strongestModule,
    weakestModule,
  };
}
