import {Chunk} from '@rechunk/api-client';

/**
 * Represents the valid entries for chunks in the `importChunk` function.
 *
 * This type is updated dynamically during the `typegen` command execution.
 * Initially, it is set to `null`, but it will be replaced with a union type of valid chunk names
 * (e.g., `'card' | 'home' | 'stack'`).
 *
 * @example
 * ```typescript
 * type ReChunkEntries = 'card' | 'home' | 'stack';
 * ```
 */
export type ReChunkEntries = null;

/**
 * Validates if a given chunk ID is part of the recognized `ReChunkEntries`.
 *
 * If the chunk ID is not valid, it produces a detailed error message prompting
 * the user to regenerate types using the `typegen` command.
 *
 * @template T - The chunk ID to validate.
 * @example
 * ```typescript
 * type ValidChunk = ValidateReChunkEntry<'card'>; // Resolves to 'card'
 * type InvalidChunk = ValidateReChunkEntry<'invalid'>;
 * // Resolves to:
 * // "Invalid ReChunk entry: 'invalid' is not a recognized chunk ID. Please regenerate types using the `typegen` command."
 * ```
 */
export type ValidateReChunkEntry<T extends string> = T extends ReChunkEntries
  ? T
  : `Error: '${T}' is not a valid ReChunk entry. To access chunks dynamically, use the 'use rechunk' directive in your component or function module.`;

/**
 * Makes all properties of a type and its nested types required recursively.
 *
 * @template T - The type to make all properties required for.
 */
export type DeepRequired<T> = Required<{
  [K in keyof T]: T[K] extends Required<T[K]> ? T[K] : DeepRequired<T[K]>;
}>;

/**
 * Represents a function that resolves a chunk ID to a chunk string asynchronously.
 * @param {string} chunkId - The ID of the chunk to resolve.
 * @returns {Promise<string>} A promise resolving to the chunk string.
 */
export type ResolverFunction = (
  chunkId: string,
) => Promise<DeepRequired<Chunk>>;

/**
 * Represents a function signature for a custom require function.
 * @template T - The type of module ID.
 */
type RequireFunction<T extends string> = (moduleId: T) => object | null;

export type Configuration = {
  resolver?: ResolverFunction;
  publicKey?: string;
  verify?: boolean;
};
