import { Request, Response, NextFunction } from 'express';
import auditMetrics from '#utils/auditMetrics';
import Logger from '#utils/logger';

/**
 * Log access to audit logs (meta-audit for compliance)
 * Enterprise systems need to track who views, exports, or searches audit logs
 */
export const auditAccessLogger = (action: 'VIEWED' | 'EXPORTED' | 'SEARCHED') => {
	return async (req: Request, res: Response, next: NextFunction) => {
		const originalSend = res.send;

		res.send = function (this: Response, data: any): Response {
			// Log after response is sent
			setImmediate(async () => {
				try {
					if (req.user) {
						const userId = (req.user as any).id;
						const userEmail = (req.user as any).email;
						const userRoles = (req.user as any).roles || [];
						const firstName = (req.user as any).first_name || '';
						const lastName = (req.user as any).last_name || '';

						await (req as any).auditLogService.enqueueSystemAudit({
							requestId: (req as any).requestId || '',
							traceId: (req as any).traceId || '',
							sessionId: (req as any).sessionId,
							actorId: userId,
							actorName: `${firstName} ${lastName}`.trim() || userEmail,
							actorEmail: userEmail,
							actorRole: Array.isArray(userRoles) ? userRoles[0] : userRoles,
							action: `AUDIT_LOG_${action}`,
							module: 'AUDIT',
							description: `Audit log ${action.toLowerCase()} by ${userEmail}`,
							severity: action === 'EXPORTED' ? 'HIGH' : 'MEDIUM',
							ipAddress: req.ip || undefined,
							userAgent: req.get('user-agent') || undefined,
							payload: {
								query_params: req.query,
								user_id: userId,
								timestamp: new Date().toISOString(),
							},
						} as any);

						// Record metric
						try {
							auditMetrics.auditLogAccess.inc({ action, user_id: userId });
						} catch {
							// Metrics optional, don't fail if not available
						}
					}
				} catch (error) {
					// Log error but don't fail the request
					Logger.error('Failed to log audit access:', error);
				}
			});

			return originalSend.call(this, data);
		};

		next();
	};
};
