// ── Dashboard ────────────────────────────────────────────────────────────────
// GET /api/dashboard?period=6months&year=2025
//   — Returns aggregated stats, trends, monthly breakdown, and recent leads.
//
// Auth: authenticated; non-admin users scoped to their own leads
//
// Periods: 7days, 30days, 6months (default), 12months, or a specific year

import { NextRequest, NextResponse } from "next/server"
import { getSessionUser } from "@/lib/auth"
import { query } from "@/lib/db"
import { avatarSvgUrl } from "@/lib/avatar"

// ── Helpers ──────────────────────────────────────────────────────────────────

/**
 * Returns the { start, end } Date range for a named period.
 */
function getPeriodDateRange(period: string): { start: Date; end: Date } {
  const end = new Date()
  let start: Date
  switch (period) {
    case "7days":
      start = new Date(end); start.setDate(start.getDate() - 7); break
    case "30days":
      start = new Date(end); start.setDate(start.getDate() - 30); break
    case "12months":
      start = new Date(end); start.setFullYear(start.getFullYear() - 12); break
    case "6months":
    default:
      start = new Date(end); start.setMonth(start.getMonth() - 6); break
  }
  return { start, end }
}

/**
 * Returns the range for the *previous* period of the same length.
 */
function getPreviousPeriodRange(period: string, currentStart: Date): { start: Date; end: Date } {
  const end = new Date(currentStart)
  const diff = end.getTime() - currentStart.getTime()
  const start = new Date(end.getTime() - diff)
  return { start, end }
}

const periodLabels: Record<string, string> = {
  "7days": "Last 7 days",
  "30days": "Last 30 days",
  "6months": "Last 6 months",
  "12months": "Last 12 months",
}

/**
 * Maps DB stage name to client-facing status string.
 */
function stageToStatus(name: string): string {
  switch (name) {
    case "New": return "open"
    case "Contacted": return "contacted"
    case "Qualified":
    case "Interested":
    case "Demo Scheduled":
    case "Negotiation": return "pending"
    case "Closed Won": return "closed"
    case "Closed Lost": return "ignored"
    default: return "open"
  }
}

/**
 * Computes a trend object from current vs previous count.
 */
function computeTrend(current: number, previous: number): { pct: number; up: boolean } {
  if (previous === 0) return { pct: current > 0 ? 100 : 0, up: current > 0 }
  const pct = Math.round(((current - previous) / previous) * 100)
  return { pct: Math.abs(pct), up: pct >= 0 }
}

// Reusable SQL snippet that maps stage names to status strings
const stageStatusSql = `
  CASE
    WHEN ls.name = 'New' THEN 'open'
    WHEN ls.name = 'Contacted' THEN 'contacted'
    WHEN ls.name IN ('Qualified', 'Interested', 'Demo Scheduled', 'Negotiation') THEN 'pending'
    WHEN ls.name = 'Closed Won' THEN 'closed'
    WHEN ls.name = 'Closed Lost' THEN 'ignored'
    ELSE 'open'
  END`

// ── GET ──────────────────────────────────────────────────────────────────────

export async function GET(request: NextRequest) {
  try {
    const user = await getSessionUser()
    if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })

    const isAdmin = user.role === "admin" || user.role === "super_admin"

    const { searchParams } = new URL(request.url)
    const period = searchParams.get("period") || "6months"
    const yearParam = searchParams.get("year")
    let start: Date, end: Date, prevRange: { start: Date; end: Date }
    if (yearParam) {
      // Year mode: compare full year to previous full year
      const y = parseInt(yearParam)
      start = new Date(y, 0, 1)
      end = new Date(y, 11, 31, 23, 59, 59)
      prevRange = { start: new Date(y - 1, 0, 1), end: new Date(y - 1, 11, 31, 23, 59, 59) }
    } else {
      const r = getPeriodDateRange(period)
      start = r.start; end = r.end
      prevRange = getPreviousPeriodRange(period, start)
    }

    // Non-admin users only see their own leads
    const ownerFilter = isAdmin ? "" : "AND l.assigned_to = $3"

    // ── Status counts for current period (SQL aggregation) ──────────
    const countSql = `
      SELECT ${stageStatusSql} AS status, COUNT(*) AS count
      FROM leads l
      JOIN lead_stages ls ON ls.id = l.stage_id
      WHERE l.deleted_at IS NULL
        AND l.created_at >= $1 AND l.created_at <= $2
        ${ownerFilter}
      GROUP BY ${stageStatusSql}`

    const currentCountRows = await query(
      countSql,
      isAdmin
        ? [start.toISOString(), end.toISOString()]
        : [start.toISOString(), end.toISOString(), user.id],
    )

    const prevCountRows = await query(
      countSql,
      isAdmin
        ? [prevRange.start.toISOString(), prevRange.end.toISOString()]
        : [prevRange.start.toISOString(), prevRange.end.toISOString(), user.id],
    )

    function rowsToCounts(rows: any[]) {
      const counts = { open: 0, contacted: 0, pending: 0, closed: 0, ignored: 0 }
      for (const r of rows) {
        const s = r.status as keyof typeof counts
        if (s in counts) counts[s] = parseInt(r.count, 10)
      }
      return counts
    }

    const currentCounts = rowsToCounts(currentCountRows.rows)
    const prevCounts = rowsToCounts(prevCountRows.rows)

    const totalLeads = currentCountRows.rows.reduce((sum: number, r: any) => sum + parseInt(r.count, 10), 0)
    const prevTotal = prevCountRows.rows.reduce((sum: number, r: any) => sum + parseInt(r.count, 10), 0)
    const closedLeads = currentCounts.closed
    const conversionRate = totalLeads > 0 ? Math.round((closedLeads / totalLeads) * 100) : 0

    // ── Monthly/weekly breakdown via date_trunc ─────────────────────
    const isMonthly = period === "6months" || period === "12months"
    const truncUnit = isMonthly ? "month" : "day"
    const breakdownSql = `
      SELECT DATE_TRUNC($1, l.created_at) AS period_start,
             ${stageStatusSql} AS status,
             COUNT(*) AS count
      FROM leads l
      JOIN lead_stages ls ON ls.id = l.stage_id
      WHERE l.deleted_at IS NULL
        AND l.created_at >= $2 AND l.created_at <= $3
        ${isAdmin ? "" : "AND l.assigned_to = $4"}
      GROUP BY DATE_TRUNC($1, l.created_at), ${stageStatusSql}
      ORDER BY period_start ASC`
    const breakdownParams = isAdmin
      ? [truncUnit, start.toISOString(), end.toISOString()]
      : [truncUnit, start.toISOString(), end.toISOString(), user.id]
    const breakdownResult = await query(breakdownSql, breakdownParams)

    // Aggregate the grouped rows into a label-keyed map
    const breakdownMap: Record<string, { label: string; total: number; open: number; contacted: number; pending: number; closed: number; ignored: number }> = {}
    for (const r of breakdownResult.rows) {
      const d = new Date(r.period_start)
      const label = isMonthly
        ? d.toLocaleDateString("en-US", { month: "short", year: "2-digit" })
        : d.toLocaleDateString("en-US", { month: "short", day: "numeric" })
      if (!breakdownMap[label]) {
        breakdownMap[label] = { label, total: 0, open: 0, contacted: 0, pending: 0, closed: 0, ignored: 0 }
      }
      const count = parseInt(r.count, 10)
      breakdownMap[label].total += count
      const statusKey = r.status as 'open' | 'contacted' | 'pending' | 'closed' | 'ignored'
      breakdownMap[label][statusKey] = count
    }
    const monthlyBreakdown = Object.values(breakdownMap)

    // ── Recent 10 leads ─────────────────────────────────────────────
    const recentSql = `
      SELECT l.id, l.created_at, l.company_name, l.contact_name, l.email, l.phone,
             l.notes, l.assigned_to, l.score,
             ls.name AS stage_name,
             u.id AS user_id, u.first_name, u.last_name, u.email AS user_email, u.avatar_url
      FROM leads l
      JOIN lead_stages ls ON ls.id = l.stage_id
      LEFT JOIN users u ON u.id = l.assigned_to
      WHERE l.deleted_at IS NULL
        AND l.created_at >= $1 AND l.created_at <= $2
        ${ownerFilter}
      ORDER BY l.created_at DESC
      LIMIT 10`
    const recentResult = await query(
      recentSql,
      isAdmin
        ? [start.toISOString(), end.toISOString()]
        : [start.toISOString(), end.toISOString(), user.id],
    )

    const recentLeads = recentResult.rows.map((r: any) => ({
      id: r.id,
      companyName: r.company_name || "",
      contactName: r.contact_name,
      email: r.email || "",
      phone: r.phone || "",
      source: "",
      description: r.notes || "",
      status: stageToStatus(r.stage_name),
      assignedUserId: r.assigned_to,
      assignedUser: r.assigned_to ? {
        id: r.user_id,
        name: `${r.first_name} ${r.last_name}`,
        email: r.user_email,
        avatar: avatarSvgUrl(`${r.first_name} ${r.last_name}`),
      } : null,
      createdAt: r.created_at,
      updatedAt: r.updated_at,
    }))

    // ── Trends (current vs previous period) ─────────────────────────
    const trends = {
      totalLeads: computeTrend(totalLeads, prevTotal),
      openLeads: computeTrend(currentCounts.open, prevCounts.open),
      contactedLeads: computeTrend(currentCounts.contacted, prevCounts.contacted),
      pendingLeads: computeTrend(currentCounts.pending, prevCounts.pending),
      closedLeads: computeTrend(currentCounts.closed, prevCounts.closed),
      conversionRate: computeTrend(conversionRate,
        prevTotal > 0 ? Math.round((prevCounts.closed / prevTotal) * 100) : 0),
    }

    const stats = {
      totalLeads,
      openLeads: currentCounts.open,
      contactedLeads: currentCounts.contacted,
      pendingLeads: currentCounts.pending,
      closedLeads,
      ignoredLeads: currentCounts.ignored,
      conversionRate,
      monthlyBreakdown,
      leadsPerMonth: monthlyBreakdown.map((m) => ({ label: m.label, leads: m.total, closed: m.closed })),
      trends,
      recentLeads,
      statusDistribution: [
        { name: "Open", value: currentCounts.open, color: "#3b82f6" },
        { name: "Contacted", value: currentCounts.contacted, color: "#f59e0b" },
        { name: "Pending", value: currentCounts.pending, color: "#8b5cf6" },
        { name: "Closed", value: currentCounts.closed, color: "#10b981" },
        { name: "Ignored", value: currentCounts.ignored, color: "#6B7280" },
      ],
      periodLabel: periodLabels[period] ?? "Selected period",
    }

    return NextResponse.json(stats)
  } catch (error) {
    console.error("Dashboard API error:", error)
    return NextResponse.json({ error: "Failed to load dashboard stats" }, { status: 500 })
  }
}
