import { z } from 'zod';

/**
 * Unified Query DSL Specification
 *
 * Based on industry best practices from:
 * - Prisma ORM
 * - Strapi CMS
 * - TypeORM
 * - LoopBack Framework
 *
 * Version: 1.0.0
 * Status: Draft
 *
 * Objective: Define a JSON-based, database-agnostic query syntax standard
 * for data filtering interactions between frontend and backend APIs.
 *
 * Design Principles:
 * 1. Declarative: Frontend describes "what data to get", not "how to query"
 * 2. Database Agnostic: Syntax contains no database-specific directives
 * 3. Type Safe: Structure can be statically inferred by TypeScript
 * 4. Convention over Configuration: Implicit syntax for common queries
 */
/**
 * Field Reference
 * Represents a reference to another field/column instead of a literal value.
 * Used for joins (ON clause) and cross-field comparisons.
 *
 * @example
 * // user.id = order.owner_id
 * { "$eq": { "$field": "order.owner_id" } }
 */
declare const FieldReferenceSchema: z.ZodObject<{
    $field: z.ZodString;
}, z.core.$strip>;
type FieldReference = z.infer<typeof FieldReferenceSchema>;
/**
 * Comparison operators for equality and inequality checks.
 * Supported data types: Any
 */
declare const EqualityOperatorSchema: z.ZodObject<{
    $eq: z.ZodOptional<z.ZodAny>;
    $ne: z.ZodOptional<z.ZodAny>;
}, z.core.$strip>;
/**
 * Comparison operators for numeric and date comparisons.
 * Supported data types: Number, Date
 */
declare const ComparisonOperatorSchema: z.ZodObject<{
    $gt: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>>;
    $gte: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>>;
    $lt: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>>;
    $lte: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>>;
}, z.core.$strip>;
/**
 * Set operators for membership checks.
 */
declare const SetOperatorSchema: z.ZodObject<{
    $in: z.ZodOptional<z.ZodArray<z.ZodAny>>;
    $nin: z.ZodOptional<z.ZodArray<z.ZodAny>>;
}, z.core.$strip>;
/**
 * Range operator for interval checks (closed interval).
 * SQL: BETWEEN ? AND ? | MongoDB: $gte AND $lte
 */
declare const RangeOperatorSchema: z.ZodObject<{
    $between: z.ZodOptional<z.ZodTuple<[z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>, z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>], null>>;
}, z.core.$strip>;
/**
 * String pattern matching operators.
 * Note: Case sensitivity should be handled at backend level.
 */
declare const StringOperatorSchema: z.ZodObject<{
    $contains: z.ZodOptional<z.ZodString>;
    $startsWith: z.ZodOptional<z.ZodString>;
    $endsWith: z.ZodOptional<z.ZodString>;
}, z.core.$strip>;
/**
 * Special check operators for null and existence.
 */
declare const SpecialOperatorSchema: z.ZodObject<{
    $null: z.ZodOptional<z.ZodBoolean>;
    $exists: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>;
/**
 * All field-level operators combined.
 * These can be applied to individual fields in a filter.
 */
declare const FieldOperatorsSchema: z.ZodObject<{
    $eq: z.ZodOptional<z.ZodAny>;
    $ne: z.ZodOptional<z.ZodAny>;
    $gt: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>>;
    $gte: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>>;
    $lt: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>>;
    $lte: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>>;
    $in: z.ZodOptional<z.ZodArray<z.ZodAny>>;
    $nin: z.ZodOptional<z.ZodArray<z.ZodAny>>;
    $between: z.ZodOptional<z.ZodTuple<[z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>, z.ZodUnion<readonly [z.ZodNumber, z.ZodDate, z.ZodObject<{
        $field: z.ZodString;
    }, z.core.$strip>]>], null>>;
    $contains: z.ZodOptional<z.ZodString>;
    $startsWith: z.ZodOptional<z.ZodString>;
    $endsWith: z.ZodOptional<z.ZodString>;
    $null: z.ZodOptional<z.ZodBoolean>;
    $exists: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>;
/**
 * Recursive filter type that supports:
 * 1. Implicit equality: { field: value }
 * 2. Explicit operators: { field: { $op: value } }
 * 3. Logical combinations: { $and: [...], $or: [...], $not: {...} }
 * 4. Nested relations: { relation: { field: value } }
 */
type FilterCondition = {
    [key: string]: any | z.infer<typeof FieldOperatorsSchema> | FilterCondition;
} & {
    /** Logical AND - combines all conditions that must be true */
    $and?: FilterCondition[];
    /** Logical OR - at least one condition must be true */
    $or?: FilterCondition[];
    /** Logical NOT - negates the condition */
    $not?: FilterCondition;
};
/**
 * Zod schema for recursive filter validation.
 * Uses z.lazy() to handle recursive structure.
 */
declare const FilterConditionSchema: z.ZodType<FilterCondition>;
/**
 * Top-level query filter wrapper.
 * This is typically used as the "where" clause in a query.
 *
 * @example
 * ```typescript
 * const filter: QueryFilter = {
 *   where: {
 *     status: "active",                    // Implicit equality
 *     age: { $gte: 18 },                   // Explicit operator
 *     $or: [                               // Logical combination
 *       { role: "admin" },
 *       { email: { $contains: "@company.com" } }
 *     ],
 *     profile: {                           // Nested relation
 *       verified: true
 *     }
 *   }
 * }
 * ```
 */
declare const QueryFilterSchema: z.ZodObject<{
    where: z.ZodOptional<z.ZodType<FilterCondition, unknown, z.core.$ZodTypeInternals<FilterCondition, unknown>>>;
}, z.core.$strip>;
/**
 * Type-safe filter operators for use in TypeScript.
 *
 * @example
 * ```typescript
 * type UserFilter = Filter<User>;
 *
 * const filter: UserFilter = {
 *   age: { $gte: 18 },
 *   email: { $contains: "@example.com" }
 * };
 * ```
 */
type Filter<T = any> = {
    [K in keyof T]?: T[K] | {
        $eq?: T[K];
        $ne?: T[K];
        $gt?: T[K] extends number | Date ? T[K] : never;
        $gte?: T[K] extends number | Date ? T[K] : never;
        $lt?: T[K] extends number | Date ? T[K] : never;
        $lte?: T[K] extends number | Date ? T[K] : never;
        $in?: T[K][];
        $nin?: T[K][];
        $between?: T[K] extends number | Date ? [T[K], T[K]] : never;
        $contains?: T[K] extends string ? string : never;
        $startsWith?: T[K] extends string ? string : never;
        $endsWith?: T[K] extends string ? string : never;
        $null?: boolean;
        $exists?: boolean;
    } | (T[K] extends object ? Filter<T[K]> : never);
} & {
    $and?: Filter<T>[];
    $or?: Filter<T>[];
    $not?: Filter<T>;
};
/**
 * Scalar types supported by the filter system.
 */
type Scalar = string | number | boolean | Date | null;
type FieldOperators = z.infer<typeof FieldOperatorsSchema>;
type QueryFilter = z.infer<typeof QueryFilterSchema>;
/**
 * Normalized filter AST structure.
 * This is the internal representation after converting all syntactic sugar
 * to explicit operators.
 *
 * Stage 1: Normalization Pass
 * Input:  { age: 18, role: "admin" }
 * Output: { $and: [{ age: { $eq: 18 } }, { role: { $eq: "admin" } }] }
 *
 * This simplifies adapter implementation by providing a consistent structure.
 */
declare const NormalizedFilterSchema: z.ZodType<any>;
type NormalizedFilter = z.infer<typeof NormalizedFilterSchema>;
/**
 * All supported operator keys.
 * Useful for validation and parsing.
 */
declare const FILTER_OPERATORS: readonly ["$eq", "$ne", "$gt", "$gte", "$lt", "$lte", "$in", "$nin", "$between", "$contains", "$startsWith", "$endsWith", "$null", "$exists"];
/**
 * Logical operator keys.
 */
declare const LOGICAL_OPERATORS: readonly ["$and", "$or", "$not"];
/**
 * All operator keys (field + logical).
 */
declare const ALL_OPERATORS: readonly ["$eq", "$ne", "$gt", "$gte", "$lt", "$lte", "$in", "$nin", "$between", "$contains", "$startsWith", "$endsWith", "$null", "$exists", "$and", "$or", "$not"];
type FilterOperatorKey = typeof FILTER_OPERATORS[number];
type LogicalOperatorKey = typeof LOGICAL_OPERATORS[number];
type OperatorKey = typeof ALL_OPERATORS[number];

export { ALL_OPERATORS as A, ComparisonOperatorSchema as C, EqualityOperatorSchema as E, type FilterCondition as F, LOGICAL_OPERATORS as L, type NormalizedFilter as N, type OperatorKey as O, type QueryFilter as Q, RangeOperatorSchema as R, type Scalar as S, FILTER_OPERATORS as a, type FieldOperators as b, FieldOperatorsSchema as c, type FieldReference as d, FieldReferenceSchema as e, type Filter as f, FilterConditionSchema as g, type FilterOperatorKey as h, type LogicalOperatorKey as i, NormalizedFilterSchema as j, QueryFilterSchema as k, SetOperatorSchema as l, SpecialOperatorSchema as m, StringOperatorSchema as n };
