/**
 * User Access Override Routes
 *
 * Per-user permission overrides for RBAC.
 * Grants add permissions on top of the user's role.
 * Denies remove permissions from the user's role.
 * All routes require authentication + super-admin role.
 */

import { Router, Request, Response } from 'express';
import { body, param, validationResult } from 'express-validator';
import { getModels } from '../models';
import { authenticate, requireRole } from '../middleware/auth';
import { asyncHandler } from '../middleware/errorHandler';
import { logAudit } from '../utils/auditLogger';
import { invalidatePermissionCache } from '../middleware/permissions';

export const userAccessOverrideRoutes = Router();

// Apply authentication and super-admin requirement to all routes
userAccessOverrideRoutes.use(authenticate);
userAccessOverrideRoutes.use(requireRole('super-admin'));

// ============================================
// GET /:userId/overrides — Get user's access overrides
// ============================================

userAccessOverrideRoutes.get(
  '/:userId/overrides',
  [param('userId').notEmpty()],
  asyncHandler(async (req: Request, res: Response) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      res.status(400).json({ error: 'Validation failed', details: errors.array() });
      return;
    }

    const { UserAccessOverride } = getModels();
    const { userId } = req.params;

    // Use the user's active company or the requester's active company
    const companyId = req.user!.activeCompanyId || (req.user!.companyIds && req.user!.companyIds[0]) || '';

    const override = await UserAccessOverride.findOne({ userId, companyId }).lean();

    if (!override) {
      res.json(null);
      return;
    }

    res.json({
      grants: (override as any).grants || [],
      denies: (override as any).denies || [],
    });
  })
);

// ============================================
// PUT /:userId/overrides — Set user's access overrides
// ============================================

userAccessOverrideRoutes.put(
  '/:userId/overrides',
  [
    param('userId').notEmpty(),
    body('grants').isArray().withMessage('Grants must be an array'),
    body('denies').isArray().withMessage('Denies must be an array'),
    body('grants.*.module').isString().notEmpty().withMessage('Each grant must have a module'),
    body('grants.*.actions').isArray().withMessage('Each grant must have an actions array'),
    body('denies.*.module').isString().notEmpty().withMessage('Each deny must have a module'),
    body('denies.*.actions').isArray().withMessage('Each deny must have an actions array'),
  ],
  asyncHandler(async (req: Request, res: Response) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      res.status(400).json({ error: 'Validation failed', details: errors.array() });
      return;
    }

    const { UserAccessOverride } = getModels();
    const { userId } = req.params;
    const { grants, denies } = req.body;

    const companyId = req.user!.activeCompanyId || (req.user!.companyIds && req.user!.companyIds[0]) || '';

    const override = await UserAccessOverride.findOneAndUpdate(
      { userId, companyId },
      {
        $set: {
          grants: grants || [],
          denies: denies || [],
        },
      },
      {
        upsert: true,
        new: true,
        runValidators: true,
      }
    ).lean();

    // Audit log
    await logAudit({
      userId: req.user!._id.toString(),
      userEmail: req.user!.email,
      action: 'permission.override',
      resource: 'Permission',
      resourceId: userId,
      companyId: companyId || undefined,
      details: { grantsCount: (grants || []).length, deniesCount: (denies || []).length },
      req,
    });

    // Invalidate permission cache for this user
    await invalidatePermissionCache(userId, companyId || undefined);

    res.json({
      grants: (override as any).grants || [],
      denies: (override as any).denies || [],
    });
  })
);

// ============================================
// DELETE /:userId/overrides — Remove user's access overrides
// ============================================

userAccessOverrideRoutes.delete(
  '/:userId/overrides',
  [param('userId').notEmpty()],
  asyncHandler(async (req: Request, res: Response) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      res.status(400).json({ error: 'Validation failed', details: errors.array() });
      return;
    }

    const { UserAccessOverride } = getModels();
    const { userId } = req.params;

    const companyId = req.user!.activeCompanyId || (req.user!.companyIds && req.user!.companyIds[0]) || '';

    await UserAccessOverride.deleteOne({ userId, companyId });

    // Audit log
    await logAudit({
      userId: req.user!._id.toString(),
      userEmail: req.user!.email,
      action: 'permission.remove',
      resource: 'Permission',
      resourceId: userId,
      companyId: companyId || undefined,
      details: { removedOverrides: true },
      req,
    });

    // Invalidate permission cache for this user
    await invalidatePermissionCache(userId, companyId || undefined);

    res.status(204).send();
  })
);

export default userAccessOverrideRoutes;