/**
 * Analytics report routes — reports-analytics (wave-10 leaf 8).
 *
 * Mounted at /api/reports (declared in index.ts router).
 *
 * Routes:
 *   GET /reports/revenue/trends?groupBy=day|week|month&start=YYYY-MM-DD&end=YYYY-MM-DD
 *   GET /reports/expenses?start=YYYY-MM-DD&end=YYYY-MM-DD
 *   GET /reports/customers?start=YYYY-MM-DD&end=YYYY-MM-DD&limit=10
 *   GET /reports/productivity?start=YYYY-MM-DD&end=YYYY-MM-DD
 *   GET /reports/overdue
 *
 * Access: requires reports:read permission.
 */
import { Hono } from 'hono'
import { z } from 'zod'
import type { AppEnv } from '../../types'
import { authMiddleware } from '../../middleware/auth'
import { requirePermission } from '../../middleware/guards'
import {
  getRevenueByPeriod,
  getExpensesByCategory,
  getTopCustomers,
  getTeamProductivity,
  getOverdueReport,
} from '@zync/db/queries'
import { withReportCache } from '../../lib/report-cache'

const analyticsRoutes = new Hono<AppEnv>()

analyticsRoutes.use('*', authMiddleware)
analyticsRoutes.use('*', requirePermission('reports:read'))

// ── Query schemas ──────────────────────────────────────────────────────────────

const dateRangeSchema = z.object({
  start: z
    .string()
    .regex(/^\d{4}-\d{2}-\d{2}$/)
    .optional(),
  end: z
    .string()
    .regex(/^\d{4}-\d{2}-\d{2}$/)
    .optional(),
})

function defaultDateRange(): { start: string; end: string } {
  const now = new Date()
  const end = now.toISOString().slice(0, 10)
  const start = new Date(now.getFullYear(), now.getMonth() - 11, 1)
    .toISOString()
    .slice(0, 10)
  return { start, end }
}

// ── GET /revenue/trends ────────────────────────────────────────────────────────

analyticsRoutes.get('/revenue/trends', async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'No tenant context' }, 403)
  }
  const tenantId = session.tid
  const db = c.get('db')

  const groupBySchema = z.enum(['day', 'week', 'month']).default('month')
  const parsedGroupBy = groupBySchema.safeParse(c.req.query('groupBy'))
  const parsedRange = dateRangeSchema.safeParse(c.req.query())

  if (!parsedGroupBy.success) {
    return c.json({ error: 'Invalid groupBy param; must be day|week|month' }, 400)
  }
  if (!parsedRange.success) {
    return c.json({ error: 'Invalid query params', details: parsedRange.error.flatten() }, 400)
  }

  const defaults = defaultDateRange()
  const start = parsedRange.data.start ?? defaults.start
  const end = parsedRange.data.end ?? defaults.end
  const groupBy = parsedGroupBy.data

  const period = `${start}_${end}_${groupBy}`
  return withReportCache(c.env, tenantId, 'revenue_trends', period, async () => {
    const rows = await getRevenueByPeriod(db, tenantId, groupBy, start, end)
    return { groupBy, start, end, rows }
  })
})

// ── GET /expenses ──────────────────────────────────────────────────────────────

analyticsRoutes.get('/expenses', async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'No tenant context' }, 403)
  }
  const tenantId = session.tid
  const db = c.get('db')

  const parsed = dateRangeSchema.safeParse(c.req.query())
  if (!parsed.success) {
    return c.json({ error: 'Invalid query params', details: parsed.error.flatten() }, 400)
  }

  const defaults = defaultDateRange()
  const start = parsed.data.start ?? defaults.start
  const end = parsed.data.end ?? defaults.end

  const period = `${start}_${end}`
  return withReportCache(c.env, tenantId, 'expenses', period, async () => {
    const rows = await getExpensesByCategory(db, tenantId, start, end)
    return { start, end, rows }
  })
})

// ── GET /customers ─────────────────────────────────────────────────────────────

analyticsRoutes.get('/customers', async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'No tenant context' }, 403)
  }
  const tenantId = session.tid
  const db = c.get('db')

  const parsed = dateRangeSchema
    .extend({ limit: z.coerce.number().int().min(1).max(100).default(10) })
    .safeParse(c.req.query())

  if (!parsed.success) {
    return c.json({ error: 'Invalid query params', details: parsed.error.flatten() }, 400)
  }

  const defaults = defaultDateRange()
  const start = parsed.data.start ?? defaults.start
  const end = parsed.data.end ?? defaults.end
  const limit = parsed.data.limit

  const period = `${start}_${end}_${limit}`
  return withReportCache(c.env, tenantId, 'customers', period, async () => {
    const rows = await getTopCustomers(db, tenantId, limit, start, end)
    return { start, end, limit, rows }
  })
})

// ── GET /productivity ──────────────────────────────────────────────────────────

analyticsRoutes.get('/productivity', async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'No tenant context' }, 403)
  }
  const tenantId = session.tid
  const db = c.get('db')

  const parsed = dateRangeSchema.safeParse(c.req.query())
  if (!parsed.success) {
    return c.json({ error: 'Invalid query params', details: parsed.error.flatten() }, 400)
  }

  const defaults = defaultDateRange()
  const start = parsed.data.start ?? defaults.start
  const end = parsed.data.end ?? defaults.end

  const period = `${start}_${end}`
  return withReportCache(c.env, tenantId, 'productivity', period, async () => {
    const rows = await getTeamProductivity(db, tenantId, start, end)
    return { start, end, rows }
  })
})

// ── GET /overdue ───────────────────────────────────────────────────────────────

analyticsRoutes.get('/overdue', async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'No tenant context' }, 403)
  }
  const tenantId = session.tid
  const db = c.get('db')

  return withReportCache(c.env, tenantId, 'overdue', 'all', async () => {
    const rows = await getOverdueReport(db, tenantId)
    return { rows }
  })
})

export { analyticsRoutes }
