import { z } from "zod";
import { createTRPCRouter, controllerProcedure } from "../trpc.js";
import {
  auditLogByEntityInputSchema,
  auditLogListInputSchema,
  auditLogTimelineInputSchema,
} from "./audit-log-inputs.js";
import {
  formatAuditDetailEntry,
  formatAuditListEntry,
  getAuditActivitySummary,
  getAuditEntriesByEntity,
  getAuditEntryById,
  getAuditTimeline,
  listAuditEntries,
  toAuditListInput,
  toAuditTimelineInput,
} from "./audit-log-support.js";

// ─── Router ───────────────────────────────────────────────────────────────────

export const auditLogRouter = createTRPCRouter({
  /**
   * Paginated, filterable list of audit log entries.
   * Cursor-based pagination using createdAt + id.
   */
  list: controllerProcedure
    .input(auditLogListInputSchema)
    .query(async ({ ctx, input }) => {
      return listAuditEntries(ctx.db, toAuditListInput({
        entityType: input.entityType,
        entityId: input.entityId,
        userId: input.userId,
        action: input.action,
        source: input.source,
        startDate: input.startDate,
        endDate: input.endDate,
        search: input.search,
        limit: input.limit,
        cursor: input.cursor,
      }));
    }),

  listDetail: controllerProcedure
    .input(auditLogListInputSchema)
    .query(async ({ ctx, input }) => {
      const result = await listAuditEntries(ctx.db, toAuditListInput({
        entityType: input.entityType,
        entityId: input.entityId,
        userId: input.userId,
        action: input.action,
        source: input.source,
        startDate: input.startDate,
        endDate: input.endDate,
        search: input.search,
        limit: input.limit,
        cursor: input.cursor,
      }));
      return {
        items: result.items.map(formatAuditListEntry),
        nextCursor: result.nextCursor ?? null,
      };
    }),

  /**
   * Get a single audit entry with full changes JSONB (for expand/detail view).
   */
  getById: controllerProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ ctx, input }) => {
      return getAuditEntryById(ctx.db, input.id);
    }),

  getByIdDetail: controllerProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ ctx, input }) => {
      const entry = await getAuditEntryById(ctx.db, input.id);
      return formatAuditDetailEntry(entry);
    }),

  /**
   * Get all audit entries for a specific entity (e.g. a project or resource).
   */
  getByEntity: controllerProcedure
    .input(auditLogByEntityInputSchema)
    .query(async ({ ctx, input }) => {
      return getAuditEntriesByEntity(ctx.db, input);
    }),

  getByEntityDetail: controllerProcedure
    .input(auditLogByEntityInputSchema)
    .query(async ({ ctx, input }) => {
      const entries = await getAuditEntriesByEntity(ctx.db, input);
      return {
        entityType: input.entityType,
        entityId: input.entityId,
        entityName: entries[0]?.entityName ?? null,
        itemCount: entries.length,
        items: entries.map(formatAuditDetailEntry),
      };
    }),

  /**
   * Timeline view: entries grouped by date (YYYY-MM-DD).
   */
  getTimeline: controllerProcedure
    .input(auditLogTimelineInputSchema)
    .query(async ({ ctx, input }) => {
      return getAuditTimeline(ctx.db, toAuditTimelineInput({
        startDate: input.startDate,
        endDate: input.endDate,
        limit: input.limit,
      }));
    }),

  getTimelineDetail: controllerProcedure
    .input(auditLogTimelineInputSchema)
    .query(async ({ ctx, input }) => {
      const timeline = await getAuditTimeline(ctx.db, toAuditTimelineInput({
        startDate: input.startDate,
        endDate: input.endDate,
        limit: input.limit,
      }));
      return Object.fromEntries(
        Object.entries(timeline).map(([dateKey, entries]) => [
          dateKey,
          entries.map(formatAuditDetailEntry),
        ]),
      );
    }),

  /**
   * Activity summary: counts by entity type, action, and user for a date range.
   */
  getActivitySummary: controllerProcedure
    .input(
      z.object({
        startDate: z.date().optional(),
        endDate: z.date().optional(),
      }),
    )
    .query(async ({ ctx, input }) => {
      return getAuditActivitySummary(ctx.db, input);
    }),
});
