#ifndef DISPATCH_H
#define DISPATCH_H

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Convolution function for standard (time, channels) layout.
 *
 * Computes: output[s, ch] = sum_k(kernel[k] * input[s+k, ch])
 * for all output samples s and channels ch.
 *
 * @param output Output buffer [n_out x channels], must be pre-allocated
 * @param kernel Convolution kernel [kernel_len]
 * @param input Input buffer [n_in x channels], n_in >= n_out + kernel_len - 1
 * @param kernel_len Length of the kernel
 * @param channels Number of channels
 * @param n_out Number of output samples
 */
typedef void (*convolve_fn_t)(
    float * __restrict__ output,
    const float * __restrict__ kernel,
    const float * __restrict__ input,
    unsigned int kernel_len,
    unsigned int channels,
    unsigned int n_out
);

/**
 * Convolution function for transposed (channels, time) layout.
 *
 * Computes: output[s] = sum_k(kernel[k] * input[s+k])
 * for all output samples s (single channel at a time).
 *
 * @param output Output buffer [n_out], must be pre-allocated
 * @param kernel Convolution kernel [kernel_len]
 * @param input Input buffer [n_in], n_in >= n_out + kernel_len - 1
 * @param kernel_len Length of the kernel
 * @param n_out Number of output samples
 */
typedef void (*convolve_transposed_fn_t)(
    float * __restrict__ output,
    const float * __restrict__ kernel,
    const float * __restrict__ input,
    unsigned int kernel_len,
    unsigned int n_out
);

/**
 * Multi-filter convolution function for groups=1 case.
 *
 * Applies multiple filters to a single input channel.
 * Computes: output[f, s] = sum_k(filters[f, k] * input[s+k])
 * for all filters f and output samples s.
 *
 * @param output Output buffer [n_filters x n_out], must be pre-allocated
 * @param filters Filter bank [n_filters x filter_len]
 * @param input Input buffer [n_in], n_in >= n_out + filter_len - 1
 * @param n_filters Number of filters
 * @param filter_len Length of each filter
 * @param n_out Number of output samples
 */
typedef void (*convolve_multi_filter_fn_t)(
    float * __restrict__ output,
    const float * __restrict__ filters,
    const float * __restrict__ input,
    unsigned int n_filters,
    unsigned int filter_len,
    unsigned int n_out
);

/**
 * Polyphase upsampling function for transposed (channels, time) layout.
 *
 * Processes all phases simultaneously per output position, keeping input
 * in cache. The kernel_T layout is [kernel_len][factor] (row = tap, col = phase).
 *
 * Computes: output[s * factor + p] = sum_k(kernel_T[k * factor + p] * input[s + k])
 * for all output positions s and phases p.
 *
 * @param output Output buffer [n_valid * factor], must be pre-allocated
 * @param kernel_T Transposed polyphase kernel [kernel_len * factor]
 * @param input Input buffer [n_samples], n_samples >= n_valid + kernel_len - 1
 * @param kernel_len Length of each phase kernel
 * @param factor Upsampling factor
 * @param n_valid Number of valid output positions
 */
typedef void (*upsample_polyphase_fn_t)(
    float * __restrict__ output,
    const float * __restrict__ kernel_T,
    const float * __restrict__ input,
    unsigned int kernel_len,
    unsigned int factor,
    unsigned int n_valid
);

/* Global function pointers - set by dispatch_init() */
extern convolve_fn_t g_convolve;
extern convolve_transposed_fn_t g_convolve_transposed;
extern convolve_multi_filter_fn_t g_convolve_multi_filter;
extern upsample_polyphase_fn_t g_upsample_polyphase;
extern const char* g_impl_name;

/**
 * Initialize dispatch table by detecting CPU features.
 * Must be called once before using g_convolve or g_convolve_transposed.
 * Safe to call multiple times.
 */
void dispatch_init(void);

/**
 * Manually select a specific implementation.
 * Useful for testing or debugging.
 *
 * @param name Implementation name (e.g., "Scalar", "AVX2+FMA", "NEON")
 * @return 0 on success, -1 if not found, -2 if CPU features unavailable
 */
int dispatch_select(const char* name);

/**
 * Get list of available implementations for this platform.
 *
 * @return NULL-terminated array of implementation names (static, do not free)
 */
const char** dispatch_get_available(void);

/**
 * Get detected CPU features as a bitmask.
 */
unsigned int dispatch_get_cpu_features(void);

#ifdef __cplusplus
}
#endif

#endif /* DISPATCH_H */
