import { Response, NextFunction } from 'express';
import { z } from 'zod';
import { permissionsService } from './permissions.service.js';
import { PermissionAction } from '../auth/entities/index.js';
import { ApiResponse, AuthenticatedRequest, ValidationError, PaginationParams } from '../../shared/types/index.js';

// Validation schemas
const checkPermissionsSchema = z.object({
  permissions: z.array(z.object({
    resource: z.string(),
    action: z.string(),
  })).min(1, 'Se requiere al menos un permiso para verificar'),
});

export class PermissionsController {
  /**
   * GET /permissions - List all permissions with optional filters
   */
  async findAll(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const page = parseInt(req.query.page as string) || 1;
      const limit = Math.min(parseInt(req.query.limit as string) || 50, 200);
      const sortBy = req.query.sortBy as string || 'resource';
      const sortOrder = (req.query.sortOrder as 'asc' | 'desc') || 'asc';

      const params: PaginationParams = { page, limit, sortBy, sortOrder };

      // Build filter
      const filter: { module?: string; resource?: string; action?: PermissionAction } = {};
      if (req.query.module) filter.module = req.query.module as string;
      if (req.query.resource) filter.resource = req.query.resource as string;
      if (req.query.action) filter.action = req.query.action as PermissionAction;

      const result = await permissionsService.findAll(params, filter);

      const response: ApiResponse = {
        success: true,
        data: result.permissions,
        meta: {
          page,
          limit,
          total: result.total,
          totalPages: Math.ceil(result.total / limit),
        },
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /permissions/modules - Get list of all modules
   */
  async getModules(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const modules = await permissionsService.getModules();

      const response: ApiResponse = {
        success: true,
        data: modules,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /permissions/resources - Get list of all resources
   */
  async getResources(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const resources = await permissionsService.getResources();

      const response: ApiResponse = {
        success: true,
        data: resources,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /permissions/grouped - Get permissions grouped by module
   */
  async getGrouped(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const grouped = await permissionsService.getGroupedByModule();

      const response: ApiResponse = {
        success: true,
        data: grouped,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /permissions/by-module/:module - Get all permissions for a module
   */
  async getByModule(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const module = req.params.module;
      const permissions = await permissionsService.getByModule(module);

      const response: ApiResponse = {
        success: true,
        data: permissions,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /permissions/matrix - Get permission matrix for admin UI
   */
  async getMatrix(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.user!.tenantId;
      const matrix = await permissionsService.getPermissionMatrix(tenantId);

      const response: ApiResponse = {
        success: true,
        data: matrix,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /permissions/me - Get current user's effective permissions
   */
  async getMyPermissions(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.user!.tenantId;
      const userId = req.user!.userId;

      const permissions = await permissionsService.getEffectivePermissions(tenantId, userId);

      const response: ApiResponse = {
        success: true,
        data: permissions,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * POST /permissions/check - Check if current user has specific permissions
   */
  async checkPermissions(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const validation = checkPermissionsSchema.safeParse(req.body);
      if (!validation.success) {
        throw new ValidationError('Datos inválidos', validation.error.errors);
      }

      const tenantId = req.user!.tenantId;
      const userId = req.user!.userId;

      const results = await permissionsService.checkPermissions(
        tenantId,
        userId,
        validation.data.permissions
      );

      const response: ApiResponse = {
        success: true,
        data: results,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /permissions/user/:userId - Get effective permissions for a specific user (admin)
   */
  async getUserPermissions(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.user!.tenantId;
      const userId = req.params.userId;

      const permissions = await permissionsService.getEffectivePermissions(tenantId, userId);

      const response: ApiResponse = {
        success: true,
        data: permissions,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }
}

export const permissionsController = new PermissionsController();
