import { Request, Response, NextFunction } from 'express';
import tokenService from '../services/token.service';
import userService from '../services/user.service';
import logger from '../utils/logger';
import { JwtPayload } from '../types/auth.types';

// Extend Express Request type to include user
declare global {
  namespace Express {
    interface Request {
      user?: {
        id:           string;   // UUID
        email:        string;
        authentikSub: string;
        role?:        string;   // populated when role is stored in DB / JWT
        groups?:      string[];
      };
    }
  }
}

/**
 * Authentication middleware
 * Validates JWT token and attaches user info to request
 */
export const authenticate = async (
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> => {
  try {
    // Extract token from Authorization header
    const authHeader = req.headers.authorization;

    if (!authHeader) {
      res.status(401).json({
        success: false,
        message: 'No authorization token provided',
      });
      return;
    }

    // Check for Bearer token format
    const parts = authHeader.split(' ');
    if (parts.length !== 2 || parts[0] !== 'Bearer') {
      res.status(401).json({
        success: false,
        message: 'Invalid authorization header format. Use: Bearer <token>',
      });
      return;
    }

    const token = parts[1];

    // Verify token
    let decoded: JwtPayload;
    try {
      decoded = tokenService.verifyToken(token);
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Invalid token';
      res.status(401).json({
        success: false,
        message,
      });
      return;
    }

    // Check if user exists and is active
    const user = await userService.findById(decoded.userId);

    if (!user) {
      logger.warn('Token valid but user not found', { userId: decoded.userId });
      res.status(401).json({
        success: false,
        message: 'User not found',
      });
      return;
    }

    if (!user.is_active) {
      logger.warn('User account is inactive', { userId: decoded.userId });
      res.status(403).json({
        success: false,
        message: 'User account is inactive',
      });
      return;
    }

    // Attach user info to request
    req.user = {
      id: decoded.userId,
      email: decoded.email,
      authentikSub: decoded.authentikSub,
      groups: decoded.groups ?? [],
      role: decoded.role,
    };

    logger.debug('User authenticated successfully', {
      userId: decoded.userId,
      email: decoded.email,
    });

    next();
  } catch (error) {
    logger.error('Authentication middleware error', { error });
    res.status(500).json({
      success: false,
      message: 'Internal server error during authentication',
    });
  }
};

/**
 * Optional authentication middleware
 * Attaches user if token is valid, but doesn't require it
 */
export const optionalAuth = async (
  req: Request,
  _res: Response,
  next: NextFunction
): Promise<void> => {
  try {
    const authHeader = req.headers.authorization;

    if (!authHeader) {
      next();
      return;
    }

    const parts = authHeader.split(' ');
    if (parts.length !== 2 || parts[0] !== 'Bearer') {
      next();
      return;
    }

    const token = parts[1];

    try {
      const decoded = tokenService.verifyToken(token);
      const user = await userService.findById(decoded.userId);

      if (user && user.is_active) {
        req.user = {
          id: decoded.userId,
          email: decoded.email,
          authentikSub: decoded.authentikSub,
          groups: decoded.groups ?? [],
        };
      }
    } catch (error) {
      // Invalid token - continue without user
      logger.debug('Optional auth: Invalid token', { error });
    }

    next();
  } catch (error) {
    logger.error('Optional authentication middleware error', { error });
    next();
  }
};
