/**
 * Example Middleware
 * Common middleware patterns for ZinTrust
 */
import { Logger } from '../../src/config/logger.js';
import { JwtSessions } from '../../src/security/JwtSessions.js';
import { XssProtection } from '../../src/security/XssProtection.js';
import { Validator } from '../../src/validation/Validator.js';
const resolveJwtManager = (jwtManager) => 'verify' in jwtManager ? jwtManager : jwtManager.create();
const resolveCsrfManager = (csrfManager) => 'validateToken' in csrfManager ? csrfManager : csrfManager.create();
const resolveSchema = (schema) => 'getRules' in schema ? schema : schema.create();
/**
 * Authentication Middleware
 * Verify user is authenticated
 */
export const authMiddleware = async (req, res, next) => {
    const token = req.getHeader('authorization');
    if (token === undefined || token === '') {
        res.setStatus(401).json({ error: 'Unauthorized' });
        return;
    }
    await next();
};
/**
 * CORS Middleware
 * Handle CORS headers
 */
export const corsMiddleware = async (req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    if (req.getMethod() === 'OPTIONS') {
        res.setStatus(200).send('');
        return;
    }
    await next();
};
/**
 * JSON Request Middleware
 * Parse JSON request bodies
 */
export const jsonMiddleware = async (req, res, next) => {
    if (req.getMethod() === 'GET' || req.getMethod() === 'DELETE') {
        await next();
        return;
    }
    if (req.isJson() === false) {
        res.setStatus(415).json({ error: 'Content-Type must be application/json' });
        return;
    }
    await next();
};
/**
 * Logging Middleware
 * Log all requests
 */
export const loggingMiddleware = async (req, res, next) => {
    const startTime = Date.now();
    const method = req.getMethod();
    const path = req.getPath();
    Logger.info(`→ ${method} ${path}`);
    await next();
    const duration = Date.now() - startTime;
    const status = res.getStatus();
    Logger.info(`← ${status} ${method} ${path} (${duration}ms)`);
};
/**
 * Rate Limiting Middleware
 * Simple in-memory rate limiting
 */
const requestCounts = new Map();
export const rateLimitMiddleware = async (req, res, next) => {
    const ip = req.getRaw().socket.remoteAddress ?? 'unknown';
    const now = Date.now();
    const windowMs = 60 * 1000; // 1 minute
    const maxRequests = 100;
    if (requestCounts.has(ip) === false) {
        requestCounts.set(ip, []);
    }
    const requests = requestCounts.get(ip) ?? [];
    const recentRequests = requests.filter((time) => now - time < windowMs);
    if (recentRequests.length >= maxRequests) {
        res.setStatus(429).json({ error: 'Too many requests' });
        return;
    }
    recentRequests.push(now);
    requestCounts.set(ip, recentRequests);
    await next();
};
/**
 * Trailing Slash Middleware
 * Redirect URLs with trailing slashes
 */
export const trailingSlashMiddleware = async (req, res, next) => {
    const path = req.getPath();
    if (path.length > 1 && path.endsWith('/') === true) {
        const withoutSlash = path.slice(0, -1);
        res.redirect(withoutSlash, 301);
        return;
    }
    await next();
};
/**
 * JWT Authentication Middleware
 * Verify JWT token and extract claims
 */
export const jwtMiddleware = (jwtManager, algorithm = 'HS256') => {
    return async (req, res, next) => {
        const authHeader = req.getHeader('authorization');
        if (authHeader === undefined || authHeader === '') {
            res.setStatus(401).json({ error: 'Missing authorization header' });
            return;
        }
        const authHeaderStr = (Array.isArray(authHeader) ? authHeader[0] : authHeader).trim();
        const [scheme, ...rest] = authHeaderStr.split(/\s+/);
        const token = rest.join(' ').trim();
        if (scheme.toLowerCase() !== 'bearer' || token === '') {
            res.setStatus(401).json({ error: 'Invalid authorization header format' });
            return;
        }
        try {
            if (!(await JwtSessions.isActive(token))) {
                res.setStatus(401).json({ error: 'Invalid or expired token' });
                return;
            }
            const payload = resolveJwtManager(jwtManager).verify(token, algorithm);
            // Store in request context (TypeScript allows dynamic properties)
            req.user = payload;
            await next();
        }
        catch (error) {
            Logger.error('JWT verification failed:', error);
            res.setStatus(401).json({ error: 'Invalid or expired token' });
        }
    };
};
export { authFailureResponder } from '../Middleware/AuthFailureResponder.js';
/**
 * CSRF Protection Middleware
 * Validate CSRF tokens for state-changing requests
 */
export const csrfMiddleware = (csrfManager) => {
    return async (req, res, next) => {
        const method = req.getMethod();
        // Only validate on state-changing requests
        if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(method) === false) {
            await next();
            return;
        }
        const sessionId = req.sessionId ?? req.getHeader('x-session-id');
        if (sessionId === undefined || sessionId === '') {
            res.setStatus(400).json({ error: 'Missing session ID' });
            return;
        }
        const csrfToken = req.getHeader('x-csrf-token');
        if (csrfToken === undefined || csrfToken === '') {
            res.setStatus(403).json({ error: 'Missing CSRF token' });
            return;
        }
        const isValid = await resolveCsrfManager(csrfManager).validateToken(String(sessionId), String(csrfToken));
        if (isValid === false) {
            res.setStatus(403).json({ error: 'Invalid or expired CSRF token' });
            return;
        }
        await next();
    };
};
/**
 * Input Validation Middleware
 * Validate request body against schema
 */
export const validationMiddleware = (schema) => {
    return async (req, res, next) => {
        if (req.getMethod() === 'GET' || req.getMethod() === 'DELETE') {
            await next();
            return;
        }
        try {
            const body = req.body ?? {};
            Validator.validate(body, resolveSchema(schema));
            await next();
        }
        catch (error) {
            Logger.error('Validation error:', error);
            const newError = error;
            if (error !== undefined &&
                'toObject' in newError &&
                typeof newError.toObject === 'function') {
                res.setStatus(422).json({ errors: newError.toObject() });
            }
            else {
                res.setStatus(400).json({ error: 'Invalid request body' });
            }
        }
    };
};
/**
 * XSS Protection Middleware
 * Sanitize and escape user input
 */
export const xssProtectionMiddleware = async (req, res, next) => {
    // Add XSS protection headers
    res.setHeader('X-Content-Type-Options', 'nosniff');
    res.setHeader('X-Frame-Options', 'DENY');
    res.setHeader('X-XSS-Protection', '1; mode=block');
    // Sanitize request body if present
    const body = req.body;
    if (body !== undefined && body !== null && typeof body === 'object') {
        for (const [key, value] of Object.entries(body)) {
            if (typeof value === 'string') {
                body[key] = XssProtection.escape(value);
            }
        }
    }
    await next();
};
