import type { Prisma } from '@prisma/client';
import prisma from '../config/db.js';

export interface AuditLogFilter {
  organizationId?: number;
  action?: string;
  sinceDays?: number;
}

// Matches blenaxis-super-admin's AuditLogEntry.target exactly — an entry
// can target an organization, a plan, a module, or settings, not just
// organizations. `id`/`label` are always plain (unencoded) values; the
// frontend encodes an organization id itself before building a link.
export interface AuditTarget {
  type: 'organization' | 'plan' | 'module' | 'settings';
  id: string;
  label: string;
}

// Matches blenaxis-super-admin's AuditChange exactly — three display
// strings, not nested objects, so AuditEntryDetail.tsx can render them
// directly as table cells.
export interface AuditChange {
  field: string;
  before: string;
  after: string;
}

export function logAudit(params: {
  target: AuditTarget;
  actorId: number | undefined;
  action: string;
  reason?: string;
  changes?: AuditChange[];
}) {
  return prisma.platformAuditLog.create({
    data: {
      actorId: params.actorId,
      action: params.action,
      reason: params.reason,
      changes: params.changes as unknown as Prisma.InputJsonValue | undefined,
      targetType: params.target.type,
      targetId: params.target.id,
      targetLabel: params.target.label,
      // Only set for organization-targeted entries — the only case the
      // `?organizationId=` list filter needs to match against.
      organizationId: params.target.type === 'organization' ? Number(params.target.id) : undefined,
    },
  });
}

const SYSTEM_ACTOR = { id: 0, name: 'System', email: '' };

export async function getAuditLogs(filter: AuditLogFilter, { skip, take }: { skip: number; take: number }) {
  const where = {
    ...(filter.organizationId ? { organizationId: filter.organizationId } : {}),
    ...(filter.action ? { action: filter.action } : {}),
    ...(filter.sinceDays ? { createdAt: { gte: new Date(Date.now() - filter.sinceDays * 24 * 60 * 60 * 1000) } } : {}),
  };

  const [rows, total] = await Promise.all([
    prisma.platformAuditLog.findMany({
      where,
      orderBy: { createdAt: 'desc' },
      skip,
      take,
      include: { actor: { select: { id: true, name: true, email: true } } },
    }),
    prisma.platformAuditLog.count({ where }),
  ]);

  const items = rows.map((row) => ({
    id: String(row.id),
    occurredAt: row.createdAt,
    actor: row.actor ?? SYSTEM_ACTOR,
    action: row.action,
    // Pre-migration rows (a handful of test entries) have no target — show
    // a generic placeholder rather than nulls the frontend isn't expecting.
    target: {
      type: (row.targetType ?? 'organization') as 'organization' | 'plan' | 'module' | 'settings',
      id: row.targetId ?? '',
      label: row.targetLabel ?? '(legacy entry)',
    },
    reason: row.reason ?? undefined,
    changes: row.changes ?? undefined,
  }));

  return { items, total };
}
