/**
 * Audit compliance routes — audit-compliance (wave-11 leaf-D).
 *
 * GET  /api/audit         — filtered, paginated tenant audit log
 * GET  /api/audit/export  — CSV download of audit log (full filtered set)
 *
 * Both routes require authMiddleware + audit: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 { createDb, listAuditLogV2 } from '@zync/db/queries'
import type { AuditLogRow, AuditListOptions } from '@zync/db/queries'
import { sanitizeCell } from '../lib/financial-export'

export const auditRoutes = new Hono<AppEnv>()

auditRoutes.use('*', authMiddleware)

// ── Zod schemas ───────────────────────────────────────────────────────────────

const auditQuerySchema = z.object({
  entity_type: z.string().optional(),
  entity_id: z.string().uuid().optional(),
  from: z.coerce.date().optional(),
  to: z.coerce.date().optional(),
  limit: z.coerce.number().int().min(1).max(100).default(50),
  offset: z.coerce.number().int().min(0).default(0),
})

const auditExportSchema = z.object({
  entity_type: z.string().optional(),
  entity_id: z.string().uuid().optional(),
  from: z.coerce.date().optional(),
  to: z.coerce.date().optional(),
})

// ── CSV helpers ───────────────────────────────────────────────────────────────

function escapeCsvField(value: string): string {
  const sanitized = sanitizeCell(value) as string
  if (sanitized.includes(',') || sanitized.includes('"') || sanitized.includes('\n')) {
    return `"${sanitized.replace(/"/g, '""')}"`
  }
  return sanitized
}

function rowToCsvLine(row: AuditLogRow): string {
  const fields = [
    row.createdAt,
    row.actorId ?? '',
    row.actorType,
    row.entityType,
    row.entityId,
    row.action,
    row.changes ? JSON.stringify(row.changes) : '',
    row.ip ?? '',
    row.requestId ?? '',
  ]
  return fields.map(escapeCsvField).join(',')
}

const CSV_HEADER = 'created_at,actor_id,actor_type,entity_type,entity_id,action,changes,ip,request_id'

// ── GET /api/audit ────────────────────────────────────────────────────────────

auditRoutes.get('/', requirePermission('audit:read'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user') {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  const parsed = auditQuerySchema.safeParse(Object.fromEntries(new URL(c.req.url).searchParams))
  if (!parsed.success) {
    return c.json({ error: 'Invalid query parameters', issues: parsed.error.issues }, 400)
  }

  const { entity_type, entity_id, from, to, limit, offset } = parsed.data
  const db = createDb(c.env)

  const opts: AuditListOptions = {
    tenantId: session.tid as string,
    entityType: entity_type,
    entityId: entity_id,
    from,
    to,
    limit,
    offset,
  }

  const { rows, total } = await listAuditLogV2(db, opts)

  return c.json({ items: rows, total, limit, offset })
})

// ── GET /api/audit/export ─────────────────────────────────────────────────────

auditRoutes.get('/export', requirePermission('audit:read'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user') {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  const parsed = auditExportSchema.safeParse(Object.fromEntries(new URL(c.req.url).searchParams))
  if (!parsed.success) {
    return c.json({ error: 'Invalid query parameters', issues: parsed.error.issues }, 400)
  }

  const { entity_type, entity_id, from, to } = parsed.data
  const db = createDb(c.env)

  const fromLabel = from ? from.toISOString().slice(0, 10) : 'all'
  const toLabel = to ? to.toISOString().slice(0, 10) : 'now'
  const filename = `audit-${fromLabel}-${toLabel}.csv`

  // Stream up to 10k rows for CSV export
  const { rows } = await listAuditLogV2(db, {
    tenantId: session.tid as string,
    entityType: entity_type,
    entityId: entity_id,
    from,
    to,
    limit: 10000,
    offset: 0,
  })

  const csv = [CSV_HEADER, ...rows.map(rowToCsvLine)].join('\n')

  return new Response(csv, {
    headers: {
      'Content-Type': 'text/csv',
      'Content-Disposition': `attachment; filename="${filename}"`,
    },
  })
})
