import { prisma } from '@/lib/prisma'

export interface SprintTokenRow {
  sprintId: string
  sprintCode: string
  sprintGoal: string
  totalTokens: number
  totalCostUsd: number
  jobCount: number
}

export interface DayTokenRow {
  day: string
  totalTokens: number
  totalCostUsd: number
}

export interface PbiTokenRow {
  pbiId: string
  pbiCode: string
  pbiTitle: string
  totalTokens: number
  totalCostUsd: number
}

type RawSprintRow = {
  sprint_id: string
  sprint_code: string
  sprint_goal: string
  total_tokens: bigint
  total_cost: number | null
  job_count: bigint
}

type RawDayRow = {
  day: Date
  total_tokens: bigint
  total_cost: number | null
}

type RawPbiRow = {
  pbi_id: string
  pbi_code: string
  pbi_title: string
  total_tokens: bigint
  total_cost: number | null
}

export async function getSprintTokenHistory(
  userId: string,
  productId?: string,
  limit = 8,
): Promise<SprintTokenRow[]> {
  const rows = productId
    ? await prisma.$queryRaw<RawSprintRow[]>`
        SELECT
          sp.id AS sprint_id,
          sp.code AS sprint_code,
          sp.sprint_goal,
          COALESCE(SUM(cj.input_tokens + cj.output_tokens + cj.cache_read_tokens + cj.cache_write_tokens + COALESCE(cj.actual_thinking_tokens, 0)), 0) AS total_tokens,
          SUM(
            cj.input_tokens  * mp.input_price_per_1m  / 1000000.0
            + cj.output_tokens * mp.output_price_per_1m / 1000000.0
            + cj.cache_read_tokens  * mp.cache_read_price_per_1m  / 1000000.0
            + cj.cache_write_tokens * mp.cache_write_price_per_1m / 1000000.0
            + COALESCE(cj.actual_thinking_tokens, 0) * mp.input_price_per_1m / 1000000.0
          ) FILTER (WHERE cj.input_tokens IS NOT NULL) AS total_cost,
          COUNT(*) FILTER (WHERE cj.input_tokens IS NOT NULL) AS job_count
        FROM claude_jobs cj
        JOIN tasks t ON cj.task_id = t.id
        JOIN stories s ON t.story_id = s.id
        JOIN sprints sp ON s.sprint_id = sp.id
        LEFT JOIN model_prices mp ON mp.model_id = cj.model_id
        WHERE cj.user_id = ${userId}
          AND cj.status = 'DONE'
          AND cj.product_id = ${productId}
        GROUP BY sp.id, sp.code, sp.sprint_goal
        ORDER BY sp.created_at DESC
        LIMIT ${limit}
      `
    : await prisma.$queryRaw<RawSprintRow[]>`
        SELECT
          sp.id AS sprint_id,
          sp.code AS sprint_code,
          sp.sprint_goal,
          COALESCE(SUM(cj.input_tokens + cj.output_tokens + cj.cache_read_tokens + cj.cache_write_tokens + COALESCE(cj.actual_thinking_tokens, 0)), 0) AS total_tokens,
          SUM(
            cj.input_tokens  * mp.input_price_per_1m  / 1000000.0
            + cj.output_tokens * mp.output_price_per_1m / 1000000.0
            + cj.cache_read_tokens  * mp.cache_read_price_per_1m  / 1000000.0
            + cj.cache_write_tokens * mp.cache_write_price_per_1m / 1000000.0
            + COALESCE(cj.actual_thinking_tokens, 0) * mp.input_price_per_1m / 1000000.0
          ) FILTER (WHERE cj.input_tokens IS NOT NULL) AS total_cost,
          COUNT(*) FILTER (WHERE cj.input_tokens IS NOT NULL) AS job_count
        FROM claude_jobs cj
        JOIN tasks t ON cj.task_id = t.id
        JOIN stories s ON t.story_id = s.id
        JOIN sprints sp ON s.sprint_id = sp.id
        LEFT JOIN model_prices mp ON mp.model_id = cj.model_id
        WHERE cj.user_id = ${userId}
          AND cj.status = 'DONE'
        GROUP BY sp.id, sp.code, sp.sprint_goal
        ORDER BY sp.created_at DESC
        LIMIT ${limit}
      `

  return rows.map(r => ({
    sprintId: r.sprint_id,
    sprintCode: r.sprint_code,
    sprintGoal: r.sprint_goal,
    totalTokens: Number(r.total_tokens),
    totalCostUsd: Number(r.total_cost ?? 0),
    jobCount: Number(r.job_count),
  }))
}

export async function getDayTokenData(userId: string, sprintId: string): Promise<DayTokenRow[]> {
  if (!sprintId) return []

  const rows = await prisma.$queryRaw<RawDayRow[]>`
    SELECT
      DATE(cj.finished_at) AS day,
      COALESCE(SUM(cj.input_tokens + cj.output_tokens + cj.cache_read_tokens + cj.cache_write_tokens + COALESCE(cj.actual_thinking_tokens, 0)), 0) AS total_tokens,
      SUM(
        cj.input_tokens  * mp.input_price_per_1m  / 1000000.0
        + cj.output_tokens * mp.output_price_per_1m / 1000000.0
        + cj.cache_read_tokens  * mp.cache_read_price_per_1m  / 1000000.0
        + cj.cache_write_tokens * mp.cache_write_price_per_1m / 1000000.0
        + COALESCE(cj.actual_thinking_tokens, 0) * mp.input_price_per_1m / 1000000.0
      ) FILTER (WHERE cj.input_tokens IS NOT NULL) AS total_cost
    FROM claude_jobs cj
    JOIN tasks t ON cj.task_id = t.id
    JOIN stories s ON t.story_id = s.id
    LEFT JOIN model_prices mp ON mp.model_id = cj.model_id
    WHERE cj.user_id = ${userId}
      AND s.sprint_id = ${sprintId}
      AND cj.status = 'DONE'
      AND cj.finished_at IS NOT NULL
    GROUP BY DATE(cj.finished_at)
    ORDER BY day ASC
  `

  return rows.map(r => ({
    day: r.day.toISOString().slice(0, 10),
    totalTokens: Number(r.total_tokens),
    totalCostUsd: Number(r.total_cost ?? 0),
  }))
}

export async function getPbiTokenAggregates(userId: string, sprintId: string): Promise<PbiTokenRow[]> {
  if (!sprintId) return []

  const rows = await prisma.$queryRaw<RawPbiRow[]>`
    SELECT
      p.id AS pbi_id,
      p.code AS pbi_code,
      p.title AS pbi_title,
      COALESCE(SUM(cj.input_tokens + cj.output_tokens + cj.cache_read_tokens + cj.cache_write_tokens + COALESCE(cj.actual_thinking_tokens, 0)), 0) AS total_tokens,
      SUM(
        cj.input_tokens  * mp.input_price_per_1m  / 1000000.0
        + cj.output_tokens * mp.output_price_per_1m / 1000000.0
        + cj.cache_read_tokens  * mp.cache_read_price_per_1m  / 1000000.0
        + cj.cache_write_tokens * mp.cache_write_price_per_1m / 1000000.0
        + COALESCE(cj.actual_thinking_tokens, 0) * mp.input_price_per_1m / 1000000.0
      ) FILTER (WHERE cj.input_tokens IS NOT NULL) AS total_cost
    FROM claude_jobs cj
    JOIN tasks t ON cj.task_id = t.id
    JOIN stories s ON t.story_id = s.id
    JOIN pbis p ON s.pbi_id = p.id
    LEFT JOIN model_prices mp ON mp.model_id = cj.model_id
    WHERE cj.user_id = ${userId}
      AND s.sprint_id = ${sprintId}
      AND cj.status = 'DONE'
    GROUP BY p.id, p.code, p.title
    ORDER BY total_cost DESC
  `

  return rows.map(r => ({
    pbiId: r.pbi_id,
    pbiCode: r.pbi_code,
    pbiTitle: r.pbi_title,
    totalTokens: Number(r.total_tokens),
    totalCostUsd: Number(r.total_cost ?? 0),
  }))
}
