/**
 * GET /api/admin/reports/export — CSV export endpoint — admin-reports-analytics.
 *
 * Exports the active tab's report data as a CSV download.
 * Guarded by requireAdminSession() + requireAdminPermission('admin.reports:view').
 */
import { Hono } from 'hono'
import { createDb } from '@zync/db/queries'
import {
  reportsExportQuerySchema,
  getRevenueReport,
  getSignupsReport,
  getTenantsReport,
  type RevenueReport,
  type SignupsReport,
  type TenantsReport,
} from '@zync/admin-analytics'
import type { AppEnv } from '../../types'
import { adminAuthMiddleware } from '../../middleware/admin-auth'
import { requireAdminSession } from '../../middleware/guards'
import { requireAdminPermission } from '@zync/auth'

const adminReportsExportRoutes = new Hono<AppEnv>()

adminReportsExportRoutes.use('*', adminAuthMiddleware)
adminReportsExportRoutes.use('*', requireAdminSession())
adminReportsExportRoutes.use('*', requireAdminPermission('admin.reports:view'))

// ── CSV utilities ─────────────────────────────────────────────────────────────

/** Escape a CSV field: quote if contains comma/quote/newline; double internal quotes.
 *  Prefix fields starting with formula-injection chars with a single quote. */
function csvField(value: unknown): string {
  const s = value == null ? '' : String(value)
  // Prevent CSV injection
  const safe = /^[=+\-@\t\r]/.test(s) ? `'${s}` : s
  // Quote if needed
  if (safe.includes(',') || safe.includes('"') || safe.includes('\n') || safe.includes('\r')) {
    return `"${safe.replace(/"/g, '""')}"`
  }
  return safe
}

function csvRow(fields: unknown[]): string {
  return fields.map(csvField).join(',')
}

function buildRevenueCsv(data: RevenueReport): string {
  const lines: string[] = [
    csvRow(['tier', 'tenants', 'mrr_ils', 'pct_of_mrr']),
    ...data.breakdown.map((r) =>
      csvRow([r.tier, r.tenants, r.mrrIls, r.pctOfMrr]),
    ),
    csvRow(['TOTAL', data.activeTenants, data.mrrIls, 100]),
  ]
  return lines.join('\r\n')
}

function buildSignupsCsv(data: SignupsReport): string {
  const lines: string[] = [
    csvRow(['month', 'tier', 'signups']),
    ...data.signupsByMonth.flatMap((bar) =>
      Object.entries(bar.byTier).map(([tier, cnt]) =>
        csvRow([bar.month, tier, cnt]),
      ),
    ),
    '',
    csvRow(['new_signups', 'churned', 'net', 'trial_conversion_pct', 'avg_trial_days']),
    csvRow([
      data.newSignups,
      data.churned,
      data.net,
      data.trialConversionPct,
      data.avgTrialDurationDays,
    ]),
  ]
  return lines.join('\r\n')
}

function buildTenantsCsv(data: TenantsReport): string {
  const lines: string[] = [
    csvRow(['slug', 'name', 'status', 'tier', 'mrr_ils', 'signup_date', 'last_login_at']),
    ...data.rows.map((r) =>
      csvRow([
        r.slug,
        r.name,
        r.status,
        r.tier,
        r.mrrIls,
        r.signupDate,
        r.lastLoginAt ?? '',
      ]),
    ),
  ]
  return lines.join('\r\n')
}

// ── Route ─────────────────────────────────────────────────────────────────────

adminReportsExportRoutes.get('/', async (c) => {
  const parsed = reportsExportQuerySchema.safeParse(c.req.query())
  if (!parsed.success) {
    return c.json({ error: 'Invalid query params', details: parsed.error.flatten() }, 400)
  }

  const { tab, from, to } = parsed.data

  const now = new Date()
  const firstOfMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1))
  const lastOfMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 0))
  const rangeFrom = from ?? firstOfMonth.toISOString().slice(0, 10)
  const rangeTo = to ?? lastOfMonth.toISOString().slice(0, 10)
  const range = { from: rangeFrom, to: rangeTo }

  const db = createDb(c.env)

  try {
    let csv: string

    if (tab === 'revenue') {
      const data = await getRevenueReport(db, range)
      csv = buildRevenueCsv(data)
    } else if (tab === 'signups') {
      const data = await getSignupsReport(db, range)
      csv = buildSignupsCsv(data)
    } else {
      // tenants — export all (no pagination limit, use large pageSize)
      const data = await getTenantsReport(db, range, 1, 100)
      // For full export, iterate pages if total > 100
      let allRows = [...data.rows]
      const totalPages = Math.ceil(data.total / 100)
      for (let p = 2; p <= totalPages; p++) {
        const more = await getTenantsReport(db, range, p, 100)
        allRows = allRows.concat(more.rows)
      }
      csv = buildTenantsCsv({ ...data, rows: allRows })
    }

    const filename = `zync-reports-${tab}-${rangeFrom}_${rangeTo}.csv`

    c.header('Content-Type', 'text/csv; charset=utf-8')
    c.header('Content-Disposition', `attachment; filename="${filename}"`)
    c.header('Cache-Control', 'private, no-store')
    return c.text(csv)
  } catch (err) {
    console.error('[admin/reports-export]', err)
    return c.json({ error: 'Internal server error' }, 500)
  }
})

export { adminReportsExportRoutes }
