/**
 * Enhanced audit logging with search capabilities
 */

import { query } from './client';
import type { CredentialAuditLog } from './credential-lifecycle';

export interface AuditSearchFilters {
  credentialId?: string;
  issuerDid?: string;
  subjectDid?: string;
  credentialType?: string | string[];
  action?: 'issued' | 'revoked' | 'verified' | 'renewed';
  performedBy?: string;
  startDate?: Date;
  endDate?: Date;
  ipAddress?: string;
}

export interface AuditSearchResult {
  logs: CredentialAuditLog[];
  total: number;
  page: number;
  pageSize: number;
}

/**
 * Search audit logs with filters
 */
export async function searchAuditLogs(
  filters: AuditSearchFilters,
  page = 1,
  pageSize = 50
): Promise<AuditSearchResult> {
  const conditions: string[] = [];
  const params: unknown[] = [];
  let paramIndex = 1;

  if (filters.credentialId) {
    conditions.push(`credential_id = $${paramIndex++}`);
    params.push(filters.credentialId);
  }

  if (filters.issuerDid) {
    conditions.push(`issuer_did = $${paramIndex++}`);
    params.push(filters.issuerDid);
  }

  if (filters.subjectDid) {
    conditions.push(`subject_did = $${paramIndex++}`);
    params.push(filters.subjectDid);
  }

  if (filters.credentialType) {
    const types = Array.isArray(filters.credentialType) ? filters.credentialType : [filters.credentialType];
    conditions.push(`credential_type && $${paramIndex++}`);
    params.push(types);
  }

  if (filters.action) {
    conditions.push(`action = $${paramIndex++}`);
    params.push(filters.action);
  }

  if (filters.performedBy) {
    conditions.push(`performed_by = $${paramIndex++}`);
    params.push(filters.performedBy);
  }

  if (filters.startDate) {
    conditions.push(`performed_at >= $${paramIndex++}`);
    params.push(filters.startDate);
  }

  if (filters.endDate) {
    conditions.push(`performed_at <= $${paramIndex++}`);
    params.push(filters.endDate);
  }

  if (filters.ipAddress) {
    conditions.push(`ip_address = $${paramIndex++}`);
    params.push(filters.ipAddress);
  }

  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
  const offset = (page - 1) * pageSize;

  // Get total count
  const countResult = await query<{ count: string }>(
    `SELECT COUNT(*) as count FROM credential_issuance_audit ${whereClause}`,
    params
  );
  const total = parseInt(countResult.rows[0]?.count || '0', 10);

  // Get paginated results
  const result = await query<CredentialAuditLog>(
    `SELECT * FROM credential_issuance_audit 
     ${whereClause}
     ORDER BY performed_at DESC 
     LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
    [...params, pageSize, offset]
  );

  return {
    logs: result.rows,
    total,
    page,
    pageSize,
  };
}

/**
 * Get audit log statistics
 */
export async function getAuditStatistics(
  startDate?: Date,
  endDate?: Date
): Promise<{
  totalIssuances: number;
  totalRevocations: number;
  totalVerifications: number;
  totalRenewals: number;
  byCredentialType: Record<string, number>;
  byAction: Record<string, number>;
}> {
  const conditions: string[] = [];
  const params: unknown[] = [];
  let paramIndex = 1;

  if (startDate) {
    conditions.push(`performed_at >= $${paramIndex++}`);
    params.push(startDate);
  }

  if (endDate) {
    conditions.push(`performed_at <= $${paramIndex++}`);
    params.push(endDate);
  }

  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';

  // Get counts by action
  const actionResult = await query<{ action: string; count: string }>(
    `SELECT action, COUNT(*) as count 
     FROM credential_issuance_audit 
     ${whereClause}
     GROUP BY action`,
    params
  );

  const byAction: Record<string, number> = {};
  actionResult.rows.forEach((row) => {
    byAction[row.action] = parseInt(row.count, 10);
  });

  // Get counts by credential type
  const typeResult = await query<{ credential_type: string[]; count: string }>(
    `SELECT credential_type, COUNT(*) as count 
     FROM credential_issuance_audit 
     ${whereClause}
     GROUP BY credential_type`,
    params
  );

  const byCredentialType: Record<string, number> = {};
  typeResult.rows.forEach((row) => {
    const types = row.credential_type.join(', ');
    byCredentialType[types] = (byCredentialType[types] || 0) + parseInt(row.count, 10);
  });

  return {
    totalIssuances: byAction.issued || 0,
    totalRevocations: byAction.revoked || 0,
    totalVerifications: byAction.verified || 0,
    totalRenewals: byAction.renewed || 0,
    byCredentialType,
    byAction,
  };
}

/**
 * Export audit logs (for compliance/regulatory reporting)
 */
export async function exportAuditLogs(
  filters: AuditSearchFilters,
  format: 'json' | 'csv' = 'json'
): Promise<string> {
  const result = await searchAuditLogs(filters, 1, 10000); // Large limit for export

  if (format === 'csv') {
    const headers = [
      'id',
      'credential_id',
      'issuer_did',
      'subject_did',
      'credential_type',
      'action',
      'performed_by',
      'performed_at',
      'ip_address',
      'user_agent',
    ];
    const rows = result.logs.map((log) => [
      log.id,
      log.credential_id,
      log.issuer_did,
      log.subject_did,
      log.credential_type.join(';'),
      log.action,
      log.performed_by || '',
      log.performed_at.toISOString(),
      log.ip_address || '',
      log.user_agent || '',
    ]);

    return [headers.join(','), ...rows.map((row) => row.join(','))].join('\n');
  }

  return JSON.stringify(result.logs, null, 2);
}

