/*
 * For any questions, contact us at: raman@worktif.com
 */

import { LambdaDefinition } from '@worktif/runtime';

import { UsersService } from '../../services/users.service';

// Type definition for our ties object
type UserHandlerTies = {
  userService: UsersService;
};

/**
 * Snapshot type for cold start initialization.
 *
 * This type defines what data is pre-loaded during Lambda cold start
 * and cached for all subsequent warm invocations.
 */
type UserHandlerSnapshot = {
  /** Application configuration loaded once during cold start */
  config: {
    maxUsersPerPage: number;
    defaultTimeout: number;
    featureFlags: {
      enableBetaFeatures: boolean;
      enableAnalytics: boolean;
    };
  };
  /** Timestamp when the Lambda execution environment was initialized */
  initTimestamp: string;
};

/**
 * Create User Handler
 *
 * Creates a new user via POST /api/users
 *
 * Request body:
 * ```json
 * {
 *   "email": "user@example.com",
 *   "name": "John Doe",
 *   "password": "securepassword123"
 * }
 * ```
 */
export const createUserHandler: LambdaDefinition<UserHandlerTies> = {
  id: 'create',
  ties: { userService: UsersService },
  handler: async (event) => {
    try {
      const body = JSON.parse(event.body || '{}');
      const { email, name, password } = body;

      if (!email || !name || !password) {
        return {
          statusCode: 400,
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ error: 'Email, name, and password are required' }),
        };
      }

      // Access userService directly from event.ties with full type safety
      const user = await event.ties.userService.createUser({ email, name, password });

      return {
        statusCode: 201,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(user),
      };
    } catch (error) {
      return {
        statusCode: 500,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          error: 'User creation failed',
          message: error instanceof Error ? error.message : 'Unknown error',
        }),
      };
    }
  },
  http: {
    method: 'POST',
    path: '/api/users',
    auth: 'none',
    cors: true,
  },
};

/**
 * Get User Handler
 *
 * Retrieves a user by ID via GET /api/users/{id}
 */
export const getUserHandler: LambdaDefinition<UserHandlerTies> = {
  id: 'get',
  ties: { userService: UsersService },
  handler: async (event) => {
    try {
      const userId = event.pathParameters?.id;

      if (!userId) {
        return {
          statusCode: 400,
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ error: 'User ID is required' }),
        };
      }

      // Access userService directly from event.ties with full type safety
      const user = await event.ties.userService.getUser(userId);

      if (!user) {
        return {
          statusCode: 404,
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ error: 'User not found' }),
        };
      }

      return {
        statusCode: 200,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(user),
      };
    } catch (error) {
      return {
        statusCode: 500,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          error: 'Failed to retrieve user',
          message: error instanceof Error ? error.message : 'Unknown error',
        }),
      };
    }
  },
  http: {
    method: 'GET',
    path: '/api/users/{id}',
    auth: 'none',
    cors: true,
  },
};

/**
 * Update User Handler
 *
 * Updates a user via PUT /api/users/{id}
 */
export const updateUserHandler: LambdaDefinition<UserHandlerTies> = {
  id: 'update',
  ties: { userService: UsersService },
  handler: async (event) => {
    try {
      const userId = event.pathParameters?.id;
      const body = JSON.parse(event.body || '{}');

      if (!userId) {
        return {
          statusCode: 400,
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ error: 'User ID is required' }),
        };
      }

      // Access userService directly from event.ties with full type safety
      const user = await event.ties.userService.updateUser(userId, body);

      return {
        statusCode: 200,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(user),
      };
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Unknown error';
      const statusCode = message === 'User not found' ? 404 : 500;

      return {
        statusCode,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          error: statusCode === 404 ? 'User not found' : 'Failed to update user',
          message,
        }),
      };
    }
  },
  http: {
    method: 'PUT',
    path: '/api/users/{id}',
    auth: 'none',
    cors: true,
  },
};

/**
 * Delete User Handler
 *
 * Deletes a user via DELETE /api/users/{id}
 */
export const deleteUserHandler: LambdaDefinition<UserHandlerTies> = {
  id: 'delete',
  ties: { userService: UsersService },
  handler: async (event) => {
    try {
      const userId = event.pathParameters?.id;

      if (!userId) {
        return {
          statusCode: 400,
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ error: 'User ID is required' }),
        };
      }

      // Access userService directly from event.ties with full type safety
      await event.ties.userService.deleteUser(userId);

      return {
        statusCode: 204,
        headers: { 'Content-Type': 'application/json' },
        body: '',
      };
    } catch (error) {
      return {
        statusCode: 500,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          error: 'Failed to delete user',
          message: error instanceof Error ? error.message : 'Unknown error',
        }),
      };
    }
  },
  http: {
    method: 'DELETE',
    path: '/api/users/{id}',
    auth: 'none',
    cors: true,
  },
};

/**
 * List Users Handler (with Cold Start Initialization)
 *
 * Demonstrates the `init` pattern for Lambda cold start optimization.
 * The init function runs once when AWS creates a new execution environment,
 * and the result is cached for all subsequent warm invocations.
 *
 * Use cases for init:
 * - Loading configuration from Parameter Store or Secrets Manager
 * - Establishing database connection pools
 * - Pre-warming SDK clients
 * - Loading feature flags or A/B test configurations
 *
 * GET /api/users
 */
export const listUsersHandler: LambdaDefinition<UserHandlerTies, UserHandlerSnapshot> = {
  id: 'list',
  ties: { userService: UsersService },

  /**
   * Cold Start Initialization Function
   *
   * This function executes exactly ONCE per Lambda execution environment (cold start).
   * The returned snapshot is cached and available via `event.snapshot` on all
   * subsequent warm invocations - no re-execution needed.
   *
   * Benefits:
   * - Expensive operations (config loading, DB connections) happen once
   * - Warm invocations are faster (no init overhead)
   * - Type-safe access to snapshot data in handler
   *
   * @param ties - Resolved DI instances (same as event.ties in handler)
   * @returns Snapshot object cached for warm invocations
   */
  init: async (ties) => {
    // Simulate loading configuration (in real app: fetch from Parameter Store, S3, etc.)
    const config = {
      maxUsersPerPage: 50,
      defaultTimeout: 30000,
      featureFlags: {
        enableBetaFeatures: process.env.ENABLE_BETA === 'true',
        enableAnalytics: true,
      },
    };

    // Log cold start for observability
    console.log('[Cold Start] Initializing Lambda execution environment');
    console.log('[Cold Start] Config loaded:', JSON.stringify(config));

    // Return snapshot - this is cached and available via event.snapshot
    return {
      config,
      initTimestamp: new Date().toISOString(),
    };
  },

  handler: async (event) => {
    try {
      // Access cached snapshot from cold start initialization
      // This data was loaded ONCE during cold start, not on every request
      const { config, initTimestamp } = event.snapshot;

      // Log to demonstrate warm vs cold invocation
      console.log(`[Handler] Using config from init at: ${initTimestamp}`);
      console.log(`[Handler] Max users per page: ${config.maxUsersPerPage}`);

      // Parse pagination from query string
      const page = parseInt(event.queryStringParameters?.page || '1', 10);
      const limit = Math.min(
        parseInt(event.queryStringParameters?.limit || '10', 10),
        config.maxUsersPerPage, // Use cached config value
      );

      // Simulate fetching users (in real app: query database)
      const users = Array.from({ length: limit }, (_, i) => ({
        id: `user_${(page - 1) * limit + i + 1}`,
        email: `user${(page - 1) * limit + i + 1}@example.com`,
        name: `User ${(page - 1) * limit + i + 1}`,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString(),
      }));

      return {
        statusCode: 200,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          users,
          pagination: {
            page,
            limit,
            maxLimit: config.maxUsersPerPage,
          },
          // Include init timestamp to demonstrate caching
          // (same timestamp across warm invocations = init ran once)
          meta: {
            initTimestamp,
            featureFlags: config.featureFlags,
          },
        }),
      };
    } catch (error) {
      return {
        statusCode: 500,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          error: 'Failed to list users',
          message: error instanceof Error ? error.message : 'Unknown error',
        }),
      };
    }
  },
  http: {
    method: 'GET',
    path: '/api/users',
    auth: 'none',
    cors: true,
  },
};
