import { z } from 'zod'
import { router, protectedProcedure, adminProcedure } from '../trpc'

export const analyticsRouter = router({
  /**
   * Get score distribution for a round (histogram data)
   */
  getScoreDistribution: adminProcedure
    .input(z.object({ roundId: z.string() }))
    .query(async ({ ctx, input }) => {
      const evaluations = await ctx.prisma.evaluation.findMany({
        where: {
          assignment: { roundId: input.roundId },
          status: 'SUBMITTED',
        },
        select: {
          criterionScoresJson: true,
        },
      })

      // Extract all scores and calculate distribution
      const allScores: number[] = []
      evaluations.forEach((evaluation) => {
        const scores = evaluation.criterionScoresJson as Record<string, number> | null
        if (scores) {
          Object.values(scores).forEach((score) => {
            if (typeof score === 'number') {
              allScores.push(score)
            }
          })
        }
      })

      // Count scores by bucket (1-10)
      const distribution = Array.from({ length: 10 }, (_, i) => ({
        score: i + 1,
        count: allScores.filter((s) => Math.round(s) === i + 1).length,
      }))

      return {
        distribution,
        totalScores: allScores.length,
        averageScore:
          allScores.length > 0
            ? allScores.reduce((a, b) => a + b, 0) / allScores.length
            : 0,
      }
    }),

  /**
   * Get evaluation completion over time (timeline data)
   */
  getEvaluationTimeline: adminProcedure
    .input(z.object({ roundId: z.string() }))
    .query(async ({ ctx, input }) => {
      const evaluations = await ctx.prisma.evaluation.findMany({
        where: {
          assignment: { roundId: input.roundId },
          status: 'SUBMITTED',
        },
        select: {
          submittedAt: true,
        },
        orderBy: { submittedAt: 'asc' },
      })

      // Group by date
      const byDate: Record<string, number> = {}
      let cumulative = 0

      evaluations.forEach((evaluation) => {
        if (evaluation.submittedAt) {
          const date = evaluation.submittedAt.toISOString().split('T')[0]
          if (!byDate[date]) {
            byDate[date] = 0
          }
          byDate[date]++
        }
      })

      // Convert to cumulative timeline
      const timeline = Object.entries(byDate)
        .sort(([a], [b]) => a.localeCompare(b))
        .map(([date, count]) => {
          cumulative += count
          return {
            date,
            daily: count,
            cumulative,
          }
        })

      return timeline
    }),

  /**
   * Get juror workload distribution
   */
  getJurorWorkload: adminProcedure
    .input(z.object({ roundId: z.string() }))
    .query(async ({ ctx, input }) => {
      const assignments = await ctx.prisma.assignment.findMany({
        where: { roundId: input.roundId },
        include: {
          user: { select: { name: true, email: true } },
          evaluation: {
            select: { id: true, status: true },
          },
        },
      })

      // Group by user
      const byUser: Record<
        string,
        { name: string; assigned: number; completed: number }
      > = {}

      assignments.forEach((assignment) => {
        const userId = assignment.userId
        if (!byUser[userId]) {
          byUser[userId] = {
            name: assignment.user.name || assignment.user.email || 'Unknown',
            assigned: 0,
            completed: 0,
          }
        }
        byUser[userId].assigned++
        if (assignment.evaluation?.status === 'SUBMITTED') {
          byUser[userId].completed++
        }
      })

      return Object.entries(byUser)
        .map(([id, data]) => ({
          id,
          ...data,
          completionRate:
            data.assigned > 0
              ? Math.round((data.completed / data.assigned) * 100)
              : 0,
        }))
        .sort((a, b) => b.assigned - a.assigned)
    }),

  /**
   * Get project rankings with average scores
   */
  getProjectRankings: adminProcedure
    .input(z.object({ roundId: z.string(), limit: z.number().optional() }))
    .query(async ({ ctx, input }) => {
      const projects = await ctx.prisma.project.findMany({
        where: { roundId: input.roundId },
        include: {
          assignments: {
            include: {
              evaluation: {
                select: { criterionScoresJson: true, status: true },
              },
            },
          },
        },
      })

      // Calculate average scores
      const rankings = projects
        .map((project) => {
          const allScores: number[] = []

          project.assignments.forEach((assignment) => {
            const evaluation = assignment.evaluation
            if (evaluation?.status === 'SUBMITTED') {
              const scores = evaluation.criterionScoresJson as Record<
                string,
                number
              > | null
              if (scores) {
                const scoreValues = Object.values(scores).filter(
                  (s): s is number => typeof s === 'number'
                )
                if (scoreValues.length > 0) {
                  const average =
                    scoreValues.reduce((a, b) => a + b, 0) / scoreValues.length
                  allScores.push(average)
                }
              }
            }
          })

          const averageScore =
            allScores.length > 0
              ? allScores.reduce((a, b) => a + b, 0) / allScores.length
              : null

          return {
            id: project.id,
            title: project.title,
            teamName: project.teamName,
            status: project.status,
            averageScore,
            evaluationCount: allScores.length,
          }
        })
        .filter((p) => p.averageScore !== null)
        .sort((a, b) => (b.averageScore || 0) - (a.averageScore || 0))

      return input.limit ? rankings.slice(0, input.limit) : rankings
    }),

  /**
   * Get status breakdown (pie chart data)
   */
  getStatusBreakdown: adminProcedure
    .input(z.object({ roundId: z.string() }))
    .query(async ({ ctx, input }) => {
      const projects = await ctx.prisma.project.groupBy({
        by: ['status'],
        where: { roundId: input.roundId },
        _count: true,
      })

      return projects.map((p) => ({
        status: p.status,
        count: p._count,
      }))
    }),

  /**
   * Get overview stats for dashboard
   */
  getOverviewStats: adminProcedure
    .input(z.object({ roundId: z.string() }))
    .query(async ({ ctx, input }) => {
      const [
        projectCount,
        assignmentCount,
        evaluationCount,
        jurorCount,
        statusCounts,
      ] = await Promise.all([
        ctx.prisma.project.count({ where: { roundId: input.roundId } }),
        ctx.prisma.assignment.count({ where: { roundId: input.roundId } }),
        ctx.prisma.evaluation.count({
          where: {
            assignment: { roundId: input.roundId },
            status: 'SUBMITTED',
          },
        }),
        ctx.prisma.assignment.groupBy({
          by: ['userId'],
          where: { roundId: input.roundId },
        }),
        ctx.prisma.project.groupBy({
          by: ['status'],
          where: { roundId: input.roundId },
          _count: true,
        }),
      ])

      const completionRate =
        assignmentCount > 0
          ? Math.round((evaluationCount / assignmentCount) * 100)
          : 0

      return {
        projectCount,
        assignmentCount,
        evaluationCount,
        jurorCount: jurorCount.length,
        completionRate,
        statusBreakdown: statusCounts.map((s) => ({
          status: s.status,
          count: s._count,
        })),
      }
    }),

  /**
   * Get criteria-level score distribution
   */
  getCriteriaScores: adminProcedure
    .input(z.object({ roundId: z.string() }))
    .query(async ({ ctx, input }) => {
      // Get active evaluation form for this round
      const evaluationForm = await ctx.prisma.evaluationForm.findFirst({
        where: { roundId: input.roundId, isActive: true },
      })

      if (!evaluationForm?.criteriaJson) {
        return []
      }

      // Parse criteria from JSON
      const criteria = evaluationForm.criteriaJson as Array<{
        id: string
        label: string
      }>

      if (!criteria || criteria.length === 0) {
        return []
      }

      // Get all evaluations
      const evaluations = await ctx.prisma.evaluation.findMany({
        where: {
          assignment: { roundId: input.roundId },
          status: 'SUBMITTED',
        },
        select: { criterionScoresJson: true },
      })

      // Calculate average score per criterion
      const criteriaScores = criteria.map((criterion) => {
        const scores: number[] = []

        evaluations.forEach((evaluation) => {
          const criterionScoresJson = evaluation.criterionScoresJson as Record<
            string,
            number
          > | null
          if (criterionScoresJson && typeof criterionScoresJson[criterion.id] === 'number') {
            scores.push(criterionScoresJson[criterion.id])
          }
        })

        return {
          id: criterion.id,
          name: criterion.label,
          averageScore:
            scores.length > 0
              ? scores.reduce((a, b) => a + b, 0) / scores.length
              : 0,
          count: scores.length,
        }
      })

      return criteriaScores
    }),

  /**
   * Get geographic distribution of projects by country
   */
  getGeographicDistribution: adminProcedure
    .input(
      z.object({
        programId: z.string(),
        roundId: z.string().optional(),
      })
    )
    .query(async ({ ctx, input }) => {
      const where = input.roundId
        ? { roundId: input.roundId }
        : { programId: input.programId }

      const distribution = await ctx.prisma.project.groupBy({
        by: ['country'],
        where,
        _count: { id: true },
      })

      return distribution.map((d) => ({
        countryCode: d.country || 'UNKNOWN',
        count: d._count.id,
      }))
    }),
})
