import "server-only";

import { WorkshopProgressStatus } from "@prisma/client";
import { prisma } from "@/lib/prisma";
import { recomputeAssessmentResults, type AssessmentSnapshot } from "@/lib/scoring";
import {
  buildStrategicRecommendations,
  computeDimensionDisplayScore,
  getGapLabel,
  getGapLevel,
  getMaturityLevel,
  getNextMaturityTarget,
  getRiskMessage,
  roundScore,
} from "@/lib/talleres/metrics";
import type { DimensionSnapshot, TalleresSnapshot, WorkshopView } from "@/lib/talleres/types";

type SnapshotOptions = {
  dimension?: string | null;
  assessmentSnapshot?: AssessmentSnapshot;
};

function toLearningObjectives(rawValue: unknown) {
  if (!Array.isArray(rawValue)) {
    return [] as string[];
  }

  return rawValue
    .map((item) => (typeof item === "string" ? item.trim() : ""))
    .filter(Boolean);
}

function getDefaultModuleOrder(moduleKey: string) {
  const fallbackOrder: Record<string, number> = {
    "liderazgo-vision-estrategica": 1,
    "cultura-organizacional": 2,
    "estructura-procesos": 3,
    "innovacion-sostenibilidad": 4,
    "impacto-social-equidad": 5,
  };

  return fallbackOrder[moduleKey] ?? 999;
}

function mapWorkshopStatus(value: WorkshopProgressStatus | null | undefined) {
  return value ?? WorkshopProgressStatus.NOT_STARTED;
}

export async function getTalleresSnapshot(userId: string, options?: SnapshotOptions): Promise<TalleresSnapshot> {
  const dimensionFilter = options?.dimension?.trim() || null;
  const assessmentSnapshot = options?.assessmentSnapshot ?? (await recomputeAssessmentResults(userId));

  const workshops = await prisma.developmentWorkshop.findMany({
    where: { isActive: true },
    include: {
      module: {
        select: {
          id: true,
          key: true,
          name: true,
          sortOrder: true,
        },
      },
      progresses: {
        where: { userId },
        take: 1,
      },
      evidences: {
        where: { userId },
        orderBy: [{ createdAt: "desc" }],
        take: 1,
      },
    },
    orderBy: [{ module: { sortOrder: "asc" } }, { sortOrder: "asc" }, { createdAt: "asc" }],
  });

  const workshopViews: WorkshopView[] = workshops.map((workshop) => {
    const progress = workshop.progresses[0];
    const latestEvidence = workshop.evidences[0];

    return {
      id: workshop.id,
      key: workshop.key,
      moduleId: workshop.moduleId,
      moduleKey: workshop.module.key,
      moduleName: workshop.module.name,
      title: workshop.title,
      summary: workshop.summary,
      videoUrl: workshop.videoUrl,
      durationMinutes: workshop.durationMinutes,
      evidenceRequired: workshop.evidenceRequired,
      learningObjectives: toLearningObjectives(workshop.learningObjectives),
      status: mapWorkshopStatus(progress?.status),
      latestEvidence: latestEvidence
        ? {
            id: latestEvidence.id,
            validationStatus: latestEvidence.validationStatus,
            validationReason: latestEvidence.validationReason,
            validationConfidence: latestEvidence.validationConfidence,
            fileName: latestEvidence.fileName,
            mimeType: latestEvidence.mimeType,
            createdAt: latestEvidence.createdAt.toISOString(),
          }
        : null,
    };
  });

  const workshopsByDimensionAll = workshopViews.reduce<Record<string, WorkshopView[]>>((accumulator, workshop) => {
    if (!accumulator[workshop.moduleKey]) {
      accumulator[workshop.moduleKey] = [];
    }

    accumulator[workshop.moduleKey].push(workshop);
    return accumulator;
  }, {});

  const scoreByModuleKey = new Map(
    assessmentSnapshot.moduleScores.map((moduleScore) => [moduleScore.moduleKey, moduleScore]),
  );

  const moduleOrder = new Map(
    assessmentSnapshot.moduleScores.map((moduleScore, index) => [moduleScore.moduleKey, index + 1]),
  );

  for (const workshop of workshops) {
    if (!moduleOrder.has(workshop.module.key)) {
      moduleOrder.set(workshop.module.key, workshop.module.sortOrder || getDefaultModuleOrder(workshop.module.key));
    }
  }

  const moduleKeys = new Set<string>([
    ...assessmentSnapshot.moduleScores.map((moduleScore) => moduleScore.moduleKey),
    ...workshops.map((workshop) => workshop.module.key),
  ]);

  const dimensions: DimensionSnapshot[] = [...moduleKeys]
    .map((moduleKey) => {
      const moduleScore = scoreByModuleKey.get(moduleKey);
      const moduleName = moduleScore?.moduleName ?? workshops.find((workshop) => workshop.module.key === moduleKey)?.module.name ?? moduleKey;
      const approvedWorkshopCount = workshopViews.filter(
        (workshop) => workshop.moduleKey === moduleKey && workshop.status === WorkshopProgressStatus.APPROVED,
      ).length;
      const workshopCount = workshopViews.filter((workshop) => workshop.moduleKey === moduleKey).length;
      const baseScore = roundScore(moduleScore?.score ?? 0);
      const displayScore = computeDimensionDisplayScore(baseScore, approvedWorkshopCount);
      const gapLevel = getGapLevel(displayScore);

      return {
        moduleId: moduleScore?.moduleId ?? workshops.find((workshop) => workshop.module.key === moduleKey)?.module.id ?? moduleKey,
        moduleKey,
        moduleName,
        baseScore,
        displayScore,
        completion: roundScore(moduleScore?.completion ?? 0),
        gapLevel,
        gapLabel: getGapLabel(gapLevel),
        riskMessage: getRiskMessage(moduleKey, displayScore),
        workshopCount,
        approvedWorkshopCount,
      };
    })
    .sort((a, b) => {
      const orderA = moduleOrder.get(a.moduleKey) ?? getDefaultModuleOrder(a.moduleKey);
      const orderB = moduleOrder.get(b.moduleKey) ?? getDefaultModuleOrder(b.moduleKey);
      return orderA - orderB;
    });

  const overallMaturity = dimensions.length
    ? roundScore(dimensions.reduce((total, dimension) => total + dimension.displayScore, 0) / dimensions.length)
    : 0;
  const maturityLevel = getMaturityLevel(overallMaturity);
  const nextLevel = getNextMaturityTarget(overallMaturity);

  const recommendations = buildStrategicRecommendations(
    dimensions.map((dimension) => ({
      moduleKey: dimension.moduleKey,
      moduleName: dimension.moduleName,
      displayScore: dimension.displayScore,
      gapLevel: dimension.gapLevel,
    })),
  );

  const workshopsByDimension =
    dimensionFilter && workshopsByDimensionAll[dimensionFilter]
      ? { [dimensionFilter]: workshopsByDimensionAll[dimensionFilter] }
      : workshopsByDimensionAll;

  const totalWorkshops = workshopViews.length;
  const approvedWorkshops = workshopViews.filter((workshop) => workshop.status === WorkshopProgressStatus.APPROVED).length;

  return {
    generatedAt: new Date().toISOString(),
    overallMaturity,
    maturityLevel,
    nextLevel,
    dimensions,
    workshopsByDimension,
    recommendations,
    summary: {
      dimensionsWithGap: dimensions.filter((dimension) => dimension.gapLevel !== "baja").length,
      currentScore: overallMaturity,
      targetScore: 100,
      totalWorkshops,
      approvedWorkshops,
    },
  };
}
