import type pg from 'pg';
import type { AuditEntry } from '../domain/security.js';

export class AuditLogger {
  constructor(private readonly pool: pg.Pool) {}

  async log(entry: AuditEntry): Promise<void> {
    await this.pool.query(
      `INSERT INTO security_audit_log (actor_id, action, target, metadata)
       VALUES ($1, $2, $3, $4)`,
      [entry.actorId, entry.action, entry.target, entry.metadata],
    );
  }

  async list(params?: {
    actorId?: string;
    action?: string;
    limit?: number;
    offset?: number;
  }): Promise<{ items: AuditEntryRow[]; total: number }> {
    const conditions: string[] = [];
    const values: unknown[] = [];
    let idx = 1;

    if (params?.actorId) {
      conditions.push(`actor_id = $${idx++}`);
      values.push(params.actorId);
    }
    if (params?.action) {
      conditions.push(`action = $${idx++}`);
      values.push(params.action);
    }

    const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
    const limit = params?.limit ?? 50;
    const offset = params?.offset ?? 0;

    const countResult = await this.pool.query<{ count: string }>(
      `SELECT COUNT(*)::text AS count FROM security_audit_log ${where}`,
      values,
    );
    const total = parseInt(countResult.rows[0]?.count ?? '0', 10);

    const result = await this.pool.query<{
      id: string;
      actor_id: string | null;
      action: string;
      target: string;
      metadata: Record<string, unknown>;
      created_at: Date;
    }>(
      `SELECT * FROM security_audit_log ${where} ORDER BY created_at DESC LIMIT $${idx++} OFFSET $${idx}`,
      [...values, limit, offset],
    );

    return {
      items: result.rows.map((row) => ({
        id: row.id,
        actorId: row.actor_id,
        action: row.action,
        target: row.target,
        metadata: row.metadata,
        createdAt: row.created_at.toISOString(),
      })),
      total,
    };
  }
}

export interface AuditEntryRow {
  id: string;
  actorId: string | null;
  action: string;
  target: string;
  metadata: Record<string, unknown>;
  createdAt: string;
}
