/**
 * Express Middleware
 * Authentication, logging, error handling
 */

import type { Request, Response, NextFunction } from 'express';
import { logger } from '../utils/logger';
import { z } from 'zod';

// ============================================================
// API KEY AUTHENTICATION
// ============================================================

/**
 * Validate API key from Authorization header
 * Expects: Authorization: Bearer <api_key>
 */
export function authenticateApiKey(req: Request, res: Response, next: NextFunction) {
  const authHeader = req.headers.authorization;

  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({
      success: false,
      error: 'Missing or invalid Authorization header',
    });
  }

  const apiKey = authHeader.slice(7); // Remove 'Bearer '
  const validApiKey = process.env.API_KEY;

  if (!validApiKey) {
    logger.error('API_KEY environment variable not configured');
    return res.status(500).json({
      success: false,
      error: 'Server misconfigured',
    });
  }

  if (apiKey !== validApiKey) {
    logger.warn({ ip: req.ip }, 'Invalid API key attempt');
    return res.status(401).json({
      success: false,
      error: 'Invalid API key',
    });
  }

  next();
}

/**
 * Optional: Allow public webhook endpoints (no auth required)
 */
export function publicEndpoint(_req: Request, _res: Response, next: NextFunction) {
  next();
}

// ============================================================
// REQUEST LOGGING
// ============================================================

/**
 * Log incoming requests
 */
export function requestLogger(req: Request, res: Response, next: NextFunction) {
  const startTime = Date.now();

  // Log response when finished
  res.on('finish', () => {
    const duration = Date.now() - startTime;
    logger.info({
      type: 'http_request',
      method: req.method,
      url: req.url,
      statusCode: res.statusCode,
      durationMs: duration,
      ip: req.ip,
      userAgent: req.headers['user-agent'],
    });
  });

  next();
}

// ============================================================
// ERROR HANDLING
// ============================================================

/**
 * Global error handler
 * Catches all unhandled errors and returns consistent JSON response
 */
export function errorHandler(
  err: Error,
  req: Request,
  res: Response,
  _next: NextFunction
) {
  logger.error({
    error: err,
    method: req.method,
    url: req.url,
    body: req.body,
  }, 'Unhandled error in request');

  // Zod validation errors
  if (err instanceof z.ZodError) {
    return res.status(400).json({
      success: false,
      error: 'Validation error',
      details: err.errors.map((e) => ({
        path: e.path.join('.'),
        message: e.message,
      })),
    });
  }

  // Default 500 error
  const isDevelopment = process.env.NODE_ENV !== 'production';
  res.status(500).json({
    success: false,
    error: 'Internal server error',
    message: isDevelopment ? err.message : undefined,
    stack: isDevelopment ? err.stack : undefined,
  });
}

/**
 * 404 handler for undefined routes
 */
export function notFoundHandler(req: Request, res: Response) {
  res.status(404).json({
    success: false,
    error: 'Route not found',
    path: req.url,
  });
}

// ============================================================
// VALIDATION HELPERS
// ============================================================

/**
 * Middleware factory for validating request body with Zod schema
 */
export function validateBody<T>(schema: z.ZodSchema<T>) {
  return (req: Request, res: Response, next: NextFunction) => {
    try {
      req.body = schema.parse(req.body);
      next();
    } catch (error) {
      if (error instanceof z.ZodError) {
        return res.status(400).json({
          success: false,
          error: 'Validation error',
          details: error.errors.map((e) => ({
            path: e.path.join('.'),
            message: e.message,
          })),
        });
      }
      next(error);
    }
  };
}

/**
 * Middleware factory for validating query parameters
 */
export function validateQuery<T>(schema: z.ZodSchema<T>) {
  return (req: Request, res: Response, next: NextFunction) => {
    try {
      req.query = schema.parse(req.query) as any;
      next();
    } catch (error) {
      if (error instanceof z.ZodError) {
        return res.status(400).json({
          success: false,
          error: 'Invalid query parameters',
          details: error.errors.map((e) => ({
            path: e.path.join('.'),
            message: e.message,
          })),
        });
      }
      next(error);
    }
  };
}

/**
 * Async handler wrapper to catch promise rejections
 */
export function asyncHandler(
  fn: (req: Request, res: Response, next: NextFunction) => Promise<any>
) {
  return (req: Request, res: Response, next: NextFunction) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
}
