/**
 * Document Audit Trail
 * Comprehensive audit logging for all document actions
 */

import { query } from './client';
import { z } from 'zod';

export const DocumentAuditLogSchema = z.object({
  id: z.string().uuid(),
  document_id: z.string().uuid().optional(),
  version_id: z.string().uuid().optional(),
  matter_id: z.string().uuid().optional(),
  action: z.string(),
  performed_by: z.string().uuid().optional(),
  performed_at: z.date(),
  ip_address: z.string().optional(),
  user_agent: z.string().optional(),
  details: z.record(z.unknown()).optional(),
  metadata: z.record(z.unknown()).optional(),
});

export type DocumentAuditLog = z.infer<typeof DocumentAuditLogSchema>;

export type DocumentAction =
  | 'created'
  | 'viewed'
  | 'downloaded'
  | 'modified'
  | 'version_created'
  | 'version_restored'
  | 'deleted'
  | 'shared'
  | 'filed'
  | 'approved'
  | 'rejected'
  | 'commented'
  | 'checked_out'
  | 'checked_in'
  | 'access_denied'
  | 'exported'
  | 'printed'
  | 'watermarked'
  | 'encrypted'
  | 'decrypted';

export interface CreateAuditLogInput {
  document_id?: string;
  version_id?: string;
  matter_id?: string;
  action: DocumentAction;
  performed_by?: string;
  ip_address?: string;
  user_agent?: string;
  details?: Record<string, unknown>;
  metadata?: Record<string, unknown>;
}

/**
 * Create audit log entry
 */
export async function createDocumentAuditLog(
  input: CreateAuditLogInput
): Promise<DocumentAuditLog> {
  const result = await query<DocumentAuditLog>(
    `INSERT INTO document_audit_log 
     (document_id, version_id, matter_id, action, performed_by, 
      ip_address, user_agent, details, metadata)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
     RETURNING *`,
    [
      input.document_id || null,
      input.version_id || null,
      input.matter_id || null,
      input.action,
      input.performed_by || null,
      input.ip_address || null,
      input.user_agent || null,
      input.details ? JSON.stringify(input.details) : null,
      input.metadata ? JSON.stringify(input.metadata) : null,
    ]
  );

  return result.rows[0]!;
}

/**
 * Search audit logs
 */
export interface AuditLogFilters {
  document_id?: string;
  version_id?: string;
  matter_id?: string;
  action?: DocumentAction | DocumentAction[];
  performed_by?: string;
  start_date?: Date;
  end_date?: Date;
  ip_address?: string;
}

export interface AuditLogSearchResult {
  logs: DocumentAuditLog[];
  total: number;
  page: number;
  page_size: number;
}

export async function searchDocumentAuditLogs(
  filters: AuditLogFilters = {},
  page = 1,
  page_size = 50
): Promise<AuditLogSearchResult> {
  const conditions: string[] = [];
  const params: unknown[] = [];
  let paramIndex = 1;

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

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

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

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

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

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

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

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

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

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

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

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

/**
 * Get audit log for a document
 */
export async function getDocumentAuditLog(
  document_id: string,
  limit = 100
): Promise<DocumentAuditLog[]> {
  const result = await query<DocumentAuditLog>(
    `SELECT * FROM document_audit_log 
     WHERE document_id = $1 
     ORDER BY performed_at DESC 
     LIMIT $2`,
    [document_id, limit]
  );
  return result.rows;
}

/**
 * Get audit log for a matter
 */
export async function getMatterAuditLog(
  matter_id: string,
  limit = 100
): Promise<DocumentAuditLog[]> {
  const result = await query<DocumentAuditLog>(
    `SELECT * FROM document_audit_log 
     WHERE matter_id = $1 
     ORDER BY performed_at DESC 
     LIMIT $2`,
    [matter_id, limit]
  );
  return result.rows;
}

/**
 * Get user activity
 */
export async function getUserDocumentActivity(
  user_id: string,
  limit = 100
): Promise<DocumentAuditLog[]> {
  const result = await query<DocumentAuditLog>(
    `SELECT * FROM document_audit_log 
     WHERE performed_by = $1 
     ORDER BY performed_at DESC 
     LIMIT $2`,
    [user_id, limit]
  );
  return result.rows;
}

/**
 * Get access log for a document (who accessed it)
 */
export async function getDocumentAccessLog(
  document_id: string
): Promise<DocumentAuditLog[]> {
  const result = await query<DocumentAuditLog>(
    `SELECT * FROM document_audit_log 
     WHERE document_id = $1 
     AND action IN ('viewed', 'downloaded', 'exported', 'printed')
     ORDER BY performed_at DESC`,
    [document_id]
  );
  return result.rows;
}

// Aliases for route compatibility
export const getDocumentAuditLogs = getDocumentAuditLog;

/**
 * Get audit statistics
 */
export interface AuditStatistics {
  total_actions: number;
  by_action: Record<string, number>;
  by_user: Record<string, number>;
  recent_activity: number; // Last 24 hours
}

export async function getAuditStatistics(
  document_id?: string,
  matter_id?: string
): Promise<AuditStatistics> {
  const conditions: string[] = [];
  const params: unknown[] = [];
  let paramIndex = 1;

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

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

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

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

  // Get by user
  const userResult = await query<{ performed_by: string; count: string }>(
    `SELECT performed_by, COUNT(*) as count 
     FROM document_audit_log 
     ${whereClause}
     AND performed_by IS NOT NULL
     GROUP BY performed_by`,
    params
  );

  // Get recent activity (last 24 hours)
  const recentResult = await query<{ count: string }>(
    `SELECT COUNT(*) as count 
     FROM document_audit_log 
     ${whereClause}
     AND performed_at >= NOW() - INTERVAL '24 hours'`,
    params
  );

  const stats: AuditStatistics = {
    total_actions: 0,
    by_action: {},
    by_user: {},
    recent_activity: parseInt(recentResult.rows[0]?.count || '0', 10),
  };

  for (const row of actionResult.rows) {
    const count = parseInt(row.count, 10);
    stats.total_actions += count;
    stats.by_action[row.action] = count;
  }

  for (const row of userResult.rows) {
    stats.by_user[row.performed_by] = parseInt(row.count, 10);
  }

  return stats;
}

