import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import * as _ from 'lodash';

/**
 * UserData - Type representing authenticated user data
 *
 * This type defines the structure of user information extracted from
 * authenticated requests. It contains the minimal essential user data
 * needed for most authorization and personalization scenarios.
 *
 * @property id - User identifier (typically from JWT 'sub' claim)
 * @property role - User role/privilege level
 * @property email - User's email address
 */
export type UserData = {
  id: string;
  role: string;
  email: string;
};

/**
 * ClientData - Custom parameter decorator for extracting authenticated user data
 *
 * This decorator extracts user information from the authenticated request
 * (typically from JWT payload stored in `req.user`) and provides it as a
 * typed UserData object to controller methods.
 *
 * Features:
 * - Safely extracts user data with lodash.get for null safety
 * - Provides typed UserData object for better TypeScript support
 * - Centralizes user data extraction logic
 * - Works with any authentication strategy that populates `req.user`
 *
 * @example
 * // Usage in controller method
 * @Get('profile')
 * getProfile(@ClientData() userData: UserData) {
 *   return this.userService.getProfile(userData.id);
 * }
 *
 * @example
 * // Extracted data format
 * {
 *   id: '12345',
 *   role: 'admin',
 *   email: 'user@example.com'
 * }
 *
 * @note Requires that authentication middleware/guard populates `req.user`
 * @note Uses lodash.get for safe property access (won't throw if undefined)
 */
export const ClientData = createParamDecorator(
  (data: unknown, ctx: ExecutionContext): UserData => {
    // Get the HTTP request object from execution context
    const request = ctx.switchToHttp().getRequest();

    // Safely extract user data from request (using lodash.get for null safety)
    const id = _.get(request, 'user.sub', '') as string; // User ID from JWT 'sub' claim
    const role = _.get(request, 'user.role', '') as string; // User role
    const email = _.get(request, 'user.email', '') as string; // User email

    // Return typed user data object
    return { id, role, email };
  },
);
