/**
 * Analytics Rollups routes.
 * Authenticated: ingest metrics. Admin: query rollups.
 */

import type { FastifyInstance } from 'fastify';
import { UnauthorizedError, ForbiddenError } from '../../lib/errors.js';
import { getRequestProductId } from '../../lib/request-context.js';
import {
  IngestMetricSchema,
  IngestBatchSchema,
  QueryRollupsSchema,
  AggregateRollupsSchema,
  SummaryQuerySchema,
  TopMetricsSchema,
} from './types.js';
import {
  ingestMetric,
  ingestBatch,
  queryRollups,
  aggregateDailyToWeekly,
  aggregateDailyToMonthly,
  getSummary,
  getTopMetrics,
  toDailyKey,
} from './repository.js';

function requireAuth(req: { jwtPayload?: { sub: string; role?: string } }): string {
  if (!req.jwtPayload?.sub) throw new UnauthorizedError('Authentication required');
  return req.jwtPayload.sub;
}

function requireAdmin(req: { jwtPayload?: { sub: string; role?: string } }): void {
  requireAuth(req);
  if (req.jwtPayload?.role !== 'admin') throw new ForbiddenError('Admin access required');
}

export async function analyticsRoutes(app: FastifyInstance): Promise<void> {
  // ── Ingest single metric ──────────────────────────────────
  app.post('/analytics/ingest', async (req, reply) => {
    requireAuth(req);
    const productId = getRequestProductId(req);
    const event = IngestMetricSchema.parse(req.body);
    await ingestMetric(productId, event);
    reply.status(202);
    return { status: 'accepted' };
  });

  // ── Ingest batch ──────────────────────────────────────────
  app.post('/analytics/ingest/batch', async (req, reply) => {
    requireAuth(req);
    const productId = getRequestProductId(req);
    const { events } = IngestBatchSchema.parse(req.body);
    const count = await ingestBatch(productId, events);
    reply.status(202);
    return { status: 'accepted', count };
  });

  // ── Admin: Query rollups ──────────────────────────────────
  app.get('/analytics/rollups', async req => {
    requireAdmin(req);
    const productId = getRequestProductId(req);
    const { period, from, to, metric } = QueryRollupsSchema.parse(req.query);
    return queryRollups(productId, period, from, to, metric);
  });

  // ── Admin: Trigger rollup aggregation ───────────────────
  app.post('/analytics/aggregate', async req => {
    requireAdmin(req);
    const productId = getRequestProductId(req);
    const { targetPeriod, sourceDate } = AggregateRollupsSchema.parse(req.body);
    const date = sourceDate ?? toDailyKey(new Date(Date.now() - 86_400_000));

    const totalEvents =
      targetPeriod === 'weekly'
        ? await aggregateDailyToWeekly(productId, date)
        : await aggregateDailyToMonthly(productId, date);

    return { targetPeriod, sourceDate: date, totalEvents };
  });

  // ── Admin: Summary dashboard ────────────────────────────
  app.get('/analytics/summary', async req => {
    requireAdmin(req);
    const productId = getRequestProductId(req);
    const { days } = SummaryQuerySchema.parse(req.query);
    return getSummary(productId, days);
  });

  // ── Admin: Top metrics for a date ───────────────────────
  app.get('/analytics/top-metrics', async req => {
    requireAdmin(req);
    const productId = getRequestProductId(req);
    const { period, date, limit } = TopMetricsSchema.parse(req.query);
    const dateKey = date ?? toDailyKey(new Date());
    return getTopMetrics(productId, period, dateKey, limit);
  });
}
