import { Reactive } from 'vue';

/**
 * Base interface for all filter types
 * @template T The type of value this filter handles
 */
interface AllowedFilter<T> {
    /** Default value when filter is not specified */
    defaultValue: T;
    /**
     * Converts a URL parameter string to filter value
     * @param value The string value from URL query parameter
     * @param delimiter Character used to split multiple values
     * @returns Properly typed filter value
     */
    parseQueryParam(value: string | null, delimiter: string): T;
    /**
     * Converts filter value to URL parameter string
     * @param value The filter value to convert
     * @param delimiter Character used to join multiple values
     * @returns String representation for URL or null if empty/default
     */
    serializeQueryParam(value: T, delimiter: string): string | null;
    /**
     * Checks if a specific value exists in the filter
     * @param filterValue Current filter value
     * @param value Value to check for
     * @returns True if value exists in filter
     */
    hasValue(filterValue: T, value: string | number): boolean;
    /**
     * Transforms filter keys for query parameter names
     * @param key Original filter key from the application
     * @returns Transformed key suitable for URL parameters
     */
    transformKey: (key: string) => string;
}
/** Map of filter keys to their filter implementation */
type Filters = Record<string, AllowedFilter<any>>;
/** Map of filter keys to their string representation for URL */
type QueryObject = Record<string, string>;
/**
 * Maps filter types to their value types using the defaultValue property
 * @template T Input type with defaultValue property
 */
type FilterValueMap<T> = T extends {
    defaultValue: infer V;
} ? V : never;
/**
 * Complete filter object with values and methods
 * @template T Filter configuration type
 */
type QueryFilters<T extends Filters> = Reactive<{
    [K in keyof T]: FilterValueMap<T[K]>;
} & FilterMethods<T>>;
type FilterState<T extends Filters> = {
    [K in keyof T]: FilterValueMap<T[K]>;
} & FilterMethods<T>;
/**
 * Configuration options for filters
 */
interface Options {
    /** Character used to separate multiple values in URL parameters */
    delimiter: string;
    /**
     * Callback triggered when filters are applied
     * @param filters The query object with current filter values
     */
    onApply?(filters: QueryObject): void;
    /**
     * When true, preserves the order of query parameters as they appear in the URL
     * @default true
     */
    preserveQueryOrder?: boolean;
    /**
     * Optional Location object to use instead of window.location (for SSR)
     */
    location?: LocationLike;
}
/**
 * Methods available on the filter object
 * @template T Type of the filters configuration
 */
interface FilterMethods<T extends Filters> {
    /**
     * Converts current filter values to URLSearchParams
     * @returns URLSearchParams object for use in fetch or URL construction
     */
    toSearchParams(): URLSearchParams;
    /**
     * Triggers the onApply callback with current filter values
     */
    get(): void;
    /**
     * Creates an object with filter keys and their string representations
     * @param transformKeys Whether to transform keys using the keyTransformer function
     * @returns Object mapping filter keys to query string values
     */
    toQueryObject(transformKeys?: boolean): Record<string, string>;
    /**
     * Creates an object with filter keys and their string representations,
     * preserving the order of parameters from the current URL
     * @param transformKeys Whether to transform keys using the keyTransformer function
     * @returns Object mapping filter keys to query string values in URL order
     */
    toOrderedQueryObject(transformKeys?: boolean): Record<string, string>;
    /**
     * Checks if a value exists in the specified filter
     * @param filter The filter key to check
     * @param value The value to look for
     * @returns True if the value exists in the filter
     */
    has<K extends keyof T>(filter: K, value: string | number): boolean;
    /**
     * Resets one or more filters to their default values
     * @param filterKey Single key or array of keys to reset
     * @param shouldGet Whether to trigger the onApply callback after clearing
     */
    clear<K extends keyof T>(filterKey: K | K[], shouldGet?: boolean): void;
    /**
     * Resets all filters to their default values
     */
    clearAll(): void;
    /**
     * Updates filter options
     * @param newOptions New options to merge with existing ones
     */
    setOptions(newOptions: Partial<Options>): void;
    /**
     * Filters data object
     * @returns Object with filter keys and their values
     */
    data(): {
        [K in keyof T]: FilterValueMap<T[K]>;
    };
}
interface SingleFilter<T> extends AllowedFilter<T> {
    defaultValue: T;
}
interface MultipleFilter<T> extends AllowedFilter<T[]> {
    defaultValue: T[];
}
interface RangeFilter<T> extends AllowedFilter<{
    from: T;
    to: T;
}> {
    defaultValue: {
        from: T;
        to: T;
    };
}
type FilterFactoryOptions = {
    keyTransformer?: (key: string) => string;
};
type LocationLike = Pick<Location, 'search'> | URL;

/**
 * Creates a collection of filter factory functions
 * @returns Object containing filter factory methods
 */

declare const createFilterFactory: (options?: FilterFactoryOptions) => {
    /**
     * Creates a filter for a single value
     * @template SingleType Type of the filter value
     * @param defaultValue Default value when filter key is not present
     * @returns A filter object handling single values
     */
    single: <SingleType>(defaultValue?: SingleType) => SingleFilter<SingleType>;
    /**
     * Creates a filter for multiple values
     * @template MultipleType Type of each item in the array
     * @param defaultValue Default array when filter key is not present
     * @returns A filter object handling arrays
     */
    multiple: <MultipleType>(defaultValue?: MultipleType[]) => MultipleFilter<MultipleType>;
    /**
     * Creates a range filter
     * @template RangeType Type of the range endpoints
     * @param defaultValue Default range when filter key is not present
     * @returns A filter object handling { from: RangeType; to: RangeType }
     */
    range: <RangeType>(defaultValue?: {
        from: RangeType;
        to: RangeType;
    }) => RangeFilter<RangeType>;
    /**
     * Allows creating a custom filter
     * @template CustomType Type of the filter value
     * @param filter A fully-defined filter object
     * @returns The same filter, for custom scenarios
     */
    custom: <CustomType>(filter: AllowedFilter<CustomType>) => AllowedFilter<CustomType>;
};

/**
 * Creates a reactive filter object from filter configurations
 * @param filters Map of filter keys to their configurations
 * @param initialOptions Initial options for the filters
 * @returns Reactive filter object with values and methods
 */
declare function useFilters<T extends Filters>(filters: T, initialOptions?: Partial<Options>): QueryFilters<T>;

/**
 * Pre-configured filter factory for convenience
 * @example
 * import { factory } from 'vue-query-filters';
 *
 * const filters = useFilters({
 *   search: factory.single<string>(),
 *   categories: factory.multiple<string>()
 * });
 */
declare const factory: {
    single: <SingleType>(defaultValue?: SingleType) => SingleFilter<SingleType>;
    multiple: <MultipleType>(defaultValue?: MultipleType[]) => MultipleFilter<MultipleType>;
    range: <RangeType>(defaultValue?: {
        from: RangeType;
        to: RangeType;
    }) => RangeFilter<RangeType>;
    custom: <CustomType>(filter: AllowedFilter<CustomType>) => AllowedFilter<CustomType>;
};

export { type AllowedFilter, type FilterFactoryOptions, type FilterMethods, type FilterState, type FilterValueMap, type Filters, type LocationLike, type MultipleFilter, type Options, type QueryFilters, type QueryObject, type RangeFilter, type SingleFilter, createFilterFactory, factory, useFilters };
