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

/**
 * SessionDataProps - Type representing session data
 *
 * This type defines the structure of session data extracted from requests.
 * It uses a generic Record type to allow flexible session storage with
 * any key-value pairs, providing maximum flexibility for different
 * session use cases.
 *
 * Common session data examples:
 * - User authentication state
 * - Shopping cart contents
 * - Form data across multiple requests
 * - User preferences
 * - Temporary OTP or verification data
 *
 * @example
 * // Session might contain:
 * {
 *   userId: 12345,
 *   cart: [{ productId: 1, quantity: 2 }],
 *   theme: 'dark',
 *   lastActivity: 1705314600000
 * }
 */
export type SessionDataProps = Record<string, any>;

/**
 * SessionData - Custom parameter decorator for extracting session data
 *
 * This decorator extracts the entire session object from the HTTP request
 * and provides it to controller methods. It's useful for scenarios where
 * you need access to the complete session rather than just user data.
 *
 * Features:
 * - Provides direct access to the full session object
 * - Works with any session storage (memory, Redis, database)
 * - Compatible with express-session, cookie-session, or custom session middleware
 * - Type-safe with SessionDataProps type
 *
 * @example
 * // Usage in controller method
 * @Get('cart')
 * getCart(@SessionData() session: SessionDataProps) {
 *   return session.cart || [];
 * }
 *
 * @example
 * // Usage with session modification
 * @Post('add-to-cart')
 * addToCart(@SessionData() session: SessionDataProps, @Body() item: CartItem) {
 *   if (!session.cart) session.cart = [];
 *   session.cart.push(item);
 *   return { success: true };
 * }
 *
 * @note Requires session middleware to be configured (e.g., express-session)
 * @note Session modifications are automatically saved by session middleware
 * @note Session data is stored server-side, session ID is sent via cookie
 */
export const SessionData = createParamDecorator(
  (data: unknown, ctx: ExecutionContext): SessionDataProps => {
    // Get the HTTP request object from execution context
    const request = ctx.switchToHttp().getRequest();

    // Return the entire session object from the request
    return request.session;
  },
);
