import { prisma } from '@/lib/prisma'
import { productAccessFilter } from '@/lib/product-access'

export type VerifyResultKey = 'ALIGNED' | 'PARTIAL' | 'EMPTY' | 'DIVERGENT'

export interface TopJob {
  jobId: string
  taskId: string
  taskTitle: string
  productId: string
  productName: string
  finishedAt: Date
}

export interface VerifyResultStats {
  counts: { result: VerifyResultKey; count: number }[]
  topEmpty: TopJob[]
  topDivergent: TopJob[]
}

export interface TrendPoint {
  sprintId: string
  sprintCode: string
  sprintGoal: string
  productName: string
  alignedRatio: number
  total: number
}

const RESULT_ORDER: VerifyResultKey[] = ['ALIGNED', 'PARTIAL', 'EMPTY', 'DIVERGENT']

export async function getVerifyResultStats(
  userId: string,
  daysBack = 30,
): Promise<VerifyResultStats> {
  const cutoff = new Date()
  cutoff.setDate(cutoff.getDate() - daysBack)

  const baseWhere = {
    user_id: userId,
    status: 'DONE' as const,
    verify_result: { not: null as null },
    finished_at: { gt: cutoff },
    // Note: task_id can now be NULL on idea-jobs (M12). The toTopJob mapper
    // filters them out via .filter(Boolean). Keeping a where-side filter
    // (`task_id: { not: null }`) is rejected by Prisma 7 runtime.
  }

  const [grouped, rawEmpty, rawDivergent] = await Promise.all([
    prisma.claudeJob.groupBy({
      by: ['verify_result'],
      where: baseWhere,
      _count: { _all: true },
    }),
    prisma.claudeJob.findMany({
      where: { ...baseWhere, verify_result: 'EMPTY' },
      orderBy: { finished_at: 'desc' },
      take: 5,
      select: {
        id: true,
        finished_at: true,
        task: { select: { id: true, title: true } },
        product: { select: { id: true, name: true } },
      },
    }),
    prisma.claudeJob.findMany({
      where: { ...baseWhere, verify_result: 'DIVERGENT' },
      orderBy: { finished_at: 'desc' },
      take: 5,
      select: {
        id: true,
        finished_at: true,
        task: { select: { id: true, title: true } },
        product: { select: { id: true, name: true } },
      },
    }),
  ])

  const countMap = new Map(
    grouped
      .filter(g => g.verify_result !== null)
      .map(g => [g.verify_result as VerifyResultKey, g._count._all]),
  )

  const counts = RESULT_ORDER
    .filter(r => countMap.has(r))
    .map(r => ({ result: r, count: countMap.get(r)! }))

  function toTopJob(j: { id: string; finished_at: Date | null; task: { id: string; title: string } | null; product: { id: string; name: string } }): TopJob | null {
    if (!j.task) return null
    return {
      jobId: j.id,
      taskId: j.task.id,
      taskTitle: j.task.title,
      productId: j.product.id,
      productName: j.product.name,
      finishedAt: j.finished_at!,
    }
  }

  return {
    counts,
    topEmpty: rawEmpty.map(toTopJob).filter((j): j is TopJob => j !== null),
    topDivergent: rawDivergent.map(toTopJob).filter((j): j is TopJob => j !== null),
  }
}

export async function getAlignmentTrend(
  userId: string,
  sprintsBack = 5,
): Promise<TrendPoint[]> {
  const sprints = await prisma.sprint.findMany({
    where: {
      status: 'CLOSED',
      product: productAccessFilter(userId),
    },
    orderBy: { completed_at: 'desc' },
    take: sprintsBack,
    select: {
      id: true,
      code: true,
      sprint_goal: true,
      completed_at: true,
      product: { select: { name: true } },
    },
  })

  const points = await Promise.all(
    sprints.map(async sprint => {
      const jobs = await prisma.claudeJob.findMany({
        where: {
          user_id: userId,
          status: 'DONE',
          verify_result: { not: null },
          task: { story: { sprint_id: sprint.id } },
        },
        select: { verify_result: true },
      })
      const aligned = jobs.filter(j => j.verify_result === 'ALIGNED').length
      return {
        sprintId: sprint.id,
        sprintCode: sprint.code,
        sprintGoal: sprint.sprint_goal,
        productName: sprint.product.name,
        alignedRatio: jobs.length > 0 ? Math.round((aligned / jobs.length) * 100) : 0,
        total: jobs.length,
      }
    }),
  )

  // chronologisch oplopend (we fetched desc, so reverse)
  return points.reverse()
}
