/**
 * Append-only audit trail for Registratura entries.
 * Server-side only — uses Prisma directly.
 */

import { prisma } from "@/core/storage/prisma";
import { Prisma } from "@prisma/client";
import type { RegistryAuditAction, RegistryAuditEvent } from "../types";

/** Log a single audit event (append-only, never updated or deleted) */
export async function logAuditEvent(params: {
  entryId: string;
  entryNumber: string;
  action: RegistryAuditAction;
  actor: string;
  actorName?: string;
  company: string;
  detail?: Record<string, unknown>;
}): Promise<void> {
  await prisma.registryAudit.create({
    data: {
      entryId: params.entryId,
      entryNumber: params.entryNumber,
      action: params.action,
      actor: params.actor,
      actorName: params.actorName ?? null,
      company: params.company,
      detail: (params.detail as Prisma.InputJsonValue) ?? Prisma.JsonNull,
    },
  });
}

/** Get chronological audit history for a single entry */
export async function getAuditHistory(
  entryId: string,
): Promise<RegistryAuditEvent[]> {
  const rows = await prisma.registryAudit.findMany({
    where: { entryId },
    orderBy: { createdAt: "asc" },
  });
  return rows.map(mapRow);
}

/** Get audit events for a company, optionally filtered by date range */
export async function getAuditByCompany(
  company: string,
  options?: { from?: string; to?: string; limit?: number },
): Promise<RegistryAuditEvent[]> {
  const where: Prisma.RegistryAuditWhereInput = { company };

  if (options?.from || options?.to) {
    const createdAt: Prisma.DateTimeFilter = {};
    if (options.from) createdAt.gte = new Date(options.from);
    if (options.to) createdAt.lte = new Date(options.to);
    where.createdAt = createdAt;
  }

  const rows = await prisma.registryAudit.findMany({
    where,
    orderBy: { createdAt: "desc" },
    take: options?.limit ?? 100,
  });
  return rows.map(mapRow);
}

/** Compute diff between old and new entry for "updated" audit events */
export function computeEntryDiff(
  oldEntry: Record<string, unknown>,
  newEntry: Record<string, unknown>,
  fieldsToTrack: string[],
): Record<string, { old: unknown; new: unknown }> | null {
  const changes: Record<string, { old: unknown; new: unknown }> = {};

  for (const field of fieldsToTrack) {
    const oldVal = oldEntry[field];
    const newVal = newEntry[field];
    if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
      changes[field] = { old: oldVal, new: newVal };
    }
  }

  return Object.keys(changes).length > 0 ? changes : null;
}

// ── Internal helpers ──

function mapRow(r: {
  id: string;
  entryId: string;
  entryNumber: string;
  action: string;
  actor: string;
  actorName: string | null;
  company: string;
  detail: Prisma.JsonValue;
  createdAt: Date;
}): RegistryAuditEvent {
  return {
    id: r.id,
    entryId: r.entryId,
    entryNumber: r.entryNumber,
    action: r.action as RegistryAuditAction,
    actor: r.actor,
    actorName: r.actorName ?? undefined,
    company: r.company,
    detail: (r.detail as Record<string, unknown>) ?? undefined,
    createdAt: r.createdAt.toISOString(),
  };
}

/** Fields tracked for update diffs */
export const TRACKED_FIELDS = [
  "subject",
  "sender",
  "recipient",
  "direction",
  "documentType",
  "status",
  "company",
  "deadline",
  "assignee",
  "date",
  "notes",
  "tags",
  "expiryDate",
];
