     1	import { buildIncludedResources } from './knex-relationship-includes.js'
     2	
     3	/**
     4	 * Processes the ?include= parameter to load related resources efficiently
     5	 *
     6	 * @param {Object} scope - The scope object for the primary resource
     7	 * @param {Array<Object>} records - The primary records to load includes for
     8	 * @param {Object} deps - Dependencies object containing log, scopes, knex, and context
     9	 * @returns {Promise<Array<Object>>} Array of included resources in JSON:API format
    10	 *
    11	 * @example
    12	 * // Input: Articles with author relationship
    13	 * const articles = [
    14	 *   { id: 1, title: 'First Article', author_id: 10 },
    15	 *   { id: 2, title: 'Second Article', author_id: 11 },
    16	 *   { id: 3, title: 'Third Article', author_id: 10 }  // Same author as article 1
    17	 * ];
    18	 *
    19	 * const deps = {
    20	 *   context: {
    21	 *     scopeName: 'articles',
    22	 *     queryParams: { include: ['author'] },
    23	 *     schemaInfo: { idProperty: 'id' }
    24	 *   }
    25	 * };
    26	 *
    27	 * const included = await processIncludes(scope, articles, deps);
    28	 *
    29	 * // Output: Deduplicated authors (only 2, not 3)
    30	 * // [
    31	 * //   { type: 'users', id: '10', attributes: { name: 'Alice', email: 'alice@example.com' } },
    32	 * //   { type: 'users', id: '11', attributes: { name: 'Bob', email: 'bob@example.com' } }
    33	 * // ]
    34	 *
    35	 * @example
    36	 * // Input: Nested includes with dot notation
    37	 * const articles = [{ id: 1, title: 'Article', author_id: 10 }];
    38	 *
    39	 * const deps = {
    40	 *   context: {
    41	 *     queryParams: {
    42	 *       include: ['author', 'comments.user'] // Load author AND comment users
    43	 *     }
    44	 *   }
    45	 * };
    46	 *
    47	 * const included = await processIncludes(scope, articles, deps);
    48	 *
    49	 * // Output: All related resources in flat array
    50	 * // [
    51	 * //   { type: 'users', id: '10', attributes: { name: 'Author' } },
    52	 * //   { type: 'comments', id: '1', attributes: { text: 'Great!' } },
    53	 * //   { type: 'comments', id: '2', attributes: { text: 'Nice!' } },
    54	 * //   { type: 'users', id: '20', attributes: { name: 'Commenter1' } },
    55	 * //   { type: 'users', id: '21', attributes: { name: 'Commenter2' } }
    56	 * // ]
    57	 *
    58	 * @example
    59	 * // Input: With sparse fieldsets limiting included data
    60	 * const deps = {
    61	 *   context: {
    62	 *     queryParams: {
    63	 *       include: ['author'],
    64	 *       fields: {
    65	 *         users: 'name'  // Only include name field for users
    66	 *       }
    67	 *     }
    68	 *   }
    69	 * };
    70	 *
    71	 * const included = await processIncludes(scope, articles, deps);
    72	 *
    73	 * // Output: Users with only requested fields
    74	 * // [
    75	 * //   { type: 'users', id: '10', attributes: { name: 'Alice' } }
    76	 * //   // email field excluded due to sparse fieldset
    77	 * // ]
    78	 *
    79	 * @description
    80	 * Used by:
    81	 * - rest-api-knex-plugin's dataGet method when includes are requested
    82	 * - rest-api-knex-plugin's dataQuery method for collection includes
    83	 * - Called after primary records are fetched but before response assembly
    84	 *
    85	 * Purpose:
    86	 * - Implements JSON:API compound documents with primary data and includes
    87	 * - Prevents N+1 queries by batch loading all related resources
    88	 * - Handles complex nested includes like 'comments.author.company'
    89	 * - Automatically deduplicates included resources
    90	 * - Respects sparse fieldsets on included resources
    91	 *
    92	 * Data flow:
    93	 * 1. Receives primary records and include directives
    94	 * 2. Parses include parameter (comma-separated, possibly nested with dots)
    95	 * 3. Delegates to buildIncludedResources for actual loading
    96	 * 4. Returns flat array of all included resources
    97	 * 5. These resources go into the 'included' section of JSON:API response
    98	 */
    99	export const processIncludes = async (scope, records, deps) => {
   100	  try {
   101	    const { log, scopes, knex, context, api } = deps
   102	
   103	    const scopeName = context.scopeName
   104	
   105	    if (!scopeName) {
   106	      log.error('[PROCESS-INCLUDES] scopeName is undefined in context!', {
   107	        contextKeys: Object.keys(context || {})
   108	      })
   109	      throw new Error('scopeName is undefined in context')
   110	    }
   111	
   112	    const db = context.transaction || knex
   113	    const queryParams = context.queryParams
   114	    const idProperty = context.schemaInfo.idProperty
   115	
   116	    if (!queryParams.include) {
   117	      return []
   118	    }
   119	
   120	    log.debug('[PROCESS-INCLUDES] Processing includes:', queryParams.include)
   121	
   122	    const includeResult = await buildIncludedResources(
   123	      {
   124	        records,
   125	        scopeName,
   126	        includeParam: queryParams.include,
   127	        fields: queryParams.fields || {},
   128	        idProperty
   129	      },
   130	      {
   131	        context: {
   132	          scopes,
   133	          log,
   134	          knex: db,
   135	          capabilities: api?.knex?.capabilities
   136	        }
   137	      }
   138	    )
   139	
   140	    log.debug('[PROCESS-INCLUDES] Include result:', {
   141	      includedCount: includeResult.included.length,
   142	      types: [...new Set(includeResult.included.map(r => r.type))]
   143	    })
   144	
   145	    return includeResult.included
   146	  } catch (error) {
   147	    const { log, context } = deps || {}
   148	
   149	    if (log) {
   150	      log.error('[PROCESS-INCLUDES] Error processing includes:', {
   151	        scopeName: context?.scopeName,
   152	        recordCount: records?.length || 0,
   153	        includeParam: context?.queryParams?.include,
   154	        error: error.message,
   155	        stack: error.stack
   156	      })
   157	    } else {
   158	      console.error('[PROCESS-INCLUDES] Error processing includes:', error)
   159	    }
   160	
   161	    const enhancedError = new Error(
   162	      `Failed to process includes${context?.scopeName ? ` for scope '${context.scopeName}'` : ''}: ${error.message}`
   163	    )
   164	    enhancedError.originalError = error
   165	    throw enhancedError
   166	  }
   167	}
