import { Request, Response, NextFunction } from 'express';
import logger from '../utils/logger';
import { auditPermissionDenied } from './audit.middleware';
import { AuditResourceType } from '../services/audit.service';
import { permissionService } from '../services/permission.service';

// ---------------------------------------------------------------------------
// AppRole — kept for backward compatibility (resolveRequestRole, bericht_text)
// ---------------------------------------------------------------------------
export type AppRole =
  | 'admin'
  | 'kommandant'
  | 'gruppenfuehrer'
  | 'mitglied'
  | 'bewerber';

/**
 * Middleware factory: requires the authenticated user to hold the given
 * permission. Permission is checked against the DB-driven permission system.
 *
 * Hardwired rules:
 * - `dashboard_admin` group always passes (full access).
 * - Maintenance mode blocks non-admin access per feature group.
 */
export function requirePermission(permission: string) {
  return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    if (!req.user) {
      res.status(401).json({
        success: false,
        message: 'Authentication required',
      });
      return;
    }

    const groups: string[] = req.user?.groups ?? [];

    // Attach resolved role for downstream use (bericht_text redaction, etc.)
    (req as any).userRole = resolveRequestRole(req);

    // Hardwired: dashboard_admin always has full access
    if (groups.includes('dashboard_admin')) {
      next();
      return;
    }

    // Check maintenance mode for the feature group
    const featureGroup = permission.split(':')[0];
    if (permissionService.isFeatureInMaintenance(featureGroup)) {
      logger.info('Feature in maintenance mode', {
        userId: req.user.id,
        featureGroup,
        permission,
        path: req.path,
      });

      res.status(403).json({
        success: false,
        message: 'Diese Funktion befindet sich im Wartungsmodus',
      });
      return;
    }

    // Check DB-driven permission
    if (!permissionService.hasPermission(groups, permission)) {
      logger.warn('Permission denied', {
        userId: req.user.id,
        groups,
        permission,
        path: req.path,
      });

      auditPermissionDenied(req, AuditResourceType.SYSTEM, undefined, {
        required_permission: permission,
        user_groups: groups,
      });

      res.status(403).json({
        success: false,
        message: 'Keine Berechtigung',
      });
      return;
    }

    next();
  };
}

/**
 * Middleware factory: passes if the user holds ANY of the listed permissions.
 * Useful when multiple roles should access the same read endpoint.
 * Maintenance mode is checked against the first permission's feature group.
 */
export function requireAnyPermission(...permissions: string[]) {
  return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    if (!req.user) {
      res.status(401).json({ success: false, message: 'Authentication required' });
      return;
    }

    const groups: string[] = req.user?.groups ?? [];
    (req as any).userRole = resolveRequestRole(req);

    if (groups.includes('dashboard_admin')) {
      next();
      return;
    }

    // Maintenance check on the feature group of the first permission
    const featureGroup = permissions[0].split(':')[0];
    if (permissionService.isFeatureInMaintenance(featureGroup)) {
      res.status(403).json({ success: false, message: 'Diese Funktion befindet sich im Wartungsmodus' });
      return;
    }

    if (permissions.some(p => permissionService.hasPermission(groups, p))) {
      next();
      return;
    }

    logger.warn('Permission denied (any-of)', {
      userId: req.user.id,
      groups,
      permissions,
      path: req.path,
    });
    auditPermissionDenied(req, AuditResourceType.SYSTEM, undefined, {
      required_permissions: permissions,
      user_groups: groups,
    });
    res.status(403).json({ success: false, message: 'Keine Berechtigung' });
  };
}

/**
 * Resolve the effective AppRole for a request.
 * Simplified: returns 'admin' for dashboard_admin, 'kommandant' for dashboard_kommando,
 * 'gruppenfuehrer' for specialist groups, else 'mitglied'.
 * Used for backward-compatible features like bericht_text redaction.
 */
export function resolveRequestRole(req: Request): AppRole {
  const groups: string[] = req.user?.groups ?? [];
  if (groups.includes('dashboard_admin')) return 'admin';
  if (groups.includes('dashboard_kommando')) return 'kommandant';
  if (
    groups.includes('dashboard_fahrmeister') ||
    groups.includes('dashboard_zeugmeister') ||
    groups.includes('dashboard_chargen')
  ) return 'gruppenfuehrer';
  return 'mitglied';
}

// Legacy exports for backward compatibility
export function getUserRole(_userId: string): Promise<AppRole> {
  return Promise.resolve('mitglied');
}

export function roleFromGroups(groups: string[]): AppRole {
  if (groups.includes('dashboard_admin')) return 'admin';
  if (groups.includes('dashboard_kommando')) return 'kommandant';
  if (groups.includes('dashboard_fahrmeister') || groups.includes('dashboard_zeugmeister') || groups.includes('dashboard_chargen')) return 'gruppenfuehrer';
  return 'mitglied';
}

export function hasPermission(role: AppRole, _permission: string): boolean {
  return role === 'admin';
}

/**
 * @deprecated Use requirePermission() instead.
 */
export function requireGroups(requiredGroups: string[]) {
  return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    if (!req.user) {
      res.status(401).json({ success: false, message: 'Authentication required' });
      return;
    }

    logger.warn('DEPRECATED: requireGroups() — migrate to requirePermission()', { requiredGroups });

    const userGroups: string[] = req.user?.groups ?? [];
    const hasAccess = requiredGroups.some(g => userGroups.includes(g));

    if (!hasAccess) {
      logger.warn('Group-based access denied', {
        userId: req.user.id,
        userGroups,
        requiredGroups,
        path: req.path,
      });

      auditPermissionDenied(req, AuditResourceType.SYSTEM, undefined, {
        required_groups: requiredGroups,
        user_groups: userGroups,
      });

      res.status(403).json({
        success: false,
        message: 'Keine Berechtigung für diese Aktion',
      });
      return;
    }

    next();
  };
}
