import { Request, Response } from 'express';
import { z } from 'zod';

import { getErrorMessage } from '../../utils/error-utils';

import { rbacService } from './rbac.service';

const AssignRoleDto = z.object({
  userId: z.string(),
  roleId: z.string(),
  expiresAt: z.string().optional(),
});

const GrantPermissionDto = z.object({
  userId: z.string(),
  permissionId: z.string(),
  expiresAt: z.string().optional(),
});

/**
 * EN: RBAC Controller
 * VI: Controller RBAC
 */
export class RBACController {
  /**
   * EN: Get user permissions
   * VI: Lấy quyền của người dùng
   */
  async getUserPermissions(req: Request, res: Response): Promise<void> {
    try {
      const userId = (req as any).user?.id || (req as any).user?.sub || req.params.userId;

      if (!userId) {
        res.status(400).json({
          success: false,
          error: { code: 'USER_ID_REQUIRED', message: 'User ID required' },
        });
        return;
      }

      const permissions = await rbacService.getUserPermissions(userId);
      const roles = await rbacService.getUserRoles(userId);

      res.json({
        success: true,
        data: {
          permissions,
          roles,
        },
      });
    } catch (error: unknown) {
      res.status(500).json({
        success: false,
        error: {
          code: 'GET_PERMISSIONS_FAILED',
          message: getErrorMessage(error) || 'Failed to get permissions',
        },
      });
    }
  }

  /**
   * EN: Assign role to user
   * VI: Gán role cho người dùng
   */
  async assignRole(req: Request, res: Response): Promise<void> {
    try {
      const data = AssignRoleDto.parse(req.body);
      const grantedBy = (req as any).user?.id || (req as any).user?.sub;

      await rbacService.assignRole(data.userId, data.roleId, {
        grantedBy,
        expiresAt: data.expiresAt ? new Date(data.expiresAt) : undefined,
      });

      res.json({
        success: true,
        data: { message: 'Role assigned successfully' },
      });
    } catch (error: unknown) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: {
            code: 'VALIDATION_ERROR',
            message: 'Invalid input',
            details: error.issues,
          },
        });
        return;
      }

      res.status(500).json({
        success: false,
        error: {
          code: 'ASSIGN_ROLE_FAILED',
          message: getErrorMessage(error) || 'Failed to assign role',
        },
      });
    }
  }

  /**
   * EN: Revoke role from user
   * VI: Thu hồi role từ người dùng
   */
  async revokeRole(req: Request, res: Response): Promise<void> {
    try {
      const { userId, roleId } = req.body;

      if (!userId || !roleId) {
        res.status(400).json({
          success: false,
          error: { code: 'INVALID_INPUT', message: 'userId and roleId required' },
        });
        return;
      }

      await rbacService.revokeRole(userId, roleId);

      res.json({
        success: true,
        data: { message: 'Role revoked successfully' },
      });
    } catch (error: unknown) {
      res.status(500).json({
        success: false,
        error: {
          code: 'REVOKE_ROLE_FAILED',
          message: getErrorMessage(error) || 'Failed to revoke role',
        },
      });
    }
  }

  /**
   * EN: Grant permission to user
   * VI: Cấp quyền cho người dùng
   */
  async grantPermission(req: Request, res: Response): Promise<void> {
    try {
      const data = GrantPermissionDto.parse(req.body);
      const grantedBy = (req as any).user?.id || (req as any).user?.sub;

      await rbacService.grantPermission(data.userId, data.permissionId, {
        grantedBy,
        expiresAt: data.expiresAt ? new Date(data.expiresAt) : undefined,
      });

      res.json({
        success: true,
        data: { message: 'Permission granted successfully' },
      });
    } catch (error: unknown) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: {
            code: 'VALIDATION_ERROR',
            message: 'Invalid input',
            details: error.issues,
          },
        });
        return;
      }

      res.status(500).json({
        success: false,
        error: {
          code: 'GRANT_PERMISSION_FAILED',
          message: getErrorMessage(error) || 'Failed to grant permission',
        },
      });
    }
  }

  /**
   * EN: Check permission
   * VI: Kiểm tra quyền
   */
  async checkPermission(req: Request, res: Response): Promise<void> {
    try {
      const userId = (req as any).user?.id || (req as any).user?.sub;
      const { resource, action, scope } = req.query;

      if (!userId || !resource || !action) {
        res.status(400).json({
          success: false,
          error: {
            code: 'INVALID_INPUT',
            message: 'userId, resource, and action are required',
          },
        });
        return;
      }

      const hasPermission = await rbacService.hasPermission(
        userId,
        resource as string,
        action as string,
        scope as string | undefined
      );

      res.json({
        success: true,
        data: { hasPermission },
      });
    } catch (error: unknown) {
      res.status(500).json({
        success: false,
        error: {
          code: 'CHECK_PERMISSION_FAILED',
          message: getErrorMessage(error) || 'Failed to check permission',
        },
      });
    }
  }
  /**
   * EN: Get all roles
   * VI: Lấy tất cả roles
   */
  async getRoles(req: Request, res: Response): Promise<void> {
    res.status(501).json({
      success: false,
      error: {
        code: 'NOT_IMPLEMENTED',
        message: 'Get roles is not yet implemented / Lấy roles chưa được triển khai'
      },
      timestamp: new Date().toISOString()
    });
  }

  /**
   * EN: Create new role
   * VI: Tạo role mới
   */
  async createRole(req: Request, res: Response): Promise<void> {
    res.status(501).json({
      success: false,
      error: {
        code: 'NOT_IMPLEMENTED',
        message: 'Create role is not yet implemented / Tạo role chưa được triển khai'
      },
      timestamp: new Date().toISOString()
    });
  }
}

export const rbacController = new RBACController();
