import { Context, InputReference, PropertyReference, PropertyReferenceString, Schema, WildcardReferenceString } from './types.js';
import { Collection } from '../collection.cjs';
export type ColumnName<TColumnNames extends string> = TColumnNames;
export type JSONLike = string | number | boolean | Date | null | Array<JSONLike> | {
    [key: string]: JSONLike;
};
export type LiteralValue = (string & {}) | number | boolean | Date | null | undefined;
export type ComparatorValue<T extends Comparator, TContext extends Context<Schema>> = T extends `in` | `not in` ? Array<LiteralValue> : PropertyReferenceString<TContext> | LiteralValue;
export type SafeString<T extends string> = T extends `@${string}` ? never : T;
export type OptionalSafeString<T extends any> = T extends string ? SafeString<T> : never;
export type LiteralValueWithSafeString<T extends any> = (OptionalSafeString<T> & {}) | number | boolean | Date | null | undefined;
export interface ExplicitLiteral {
    value: JSONLike;
}
export type AllowedFunctionName = `DATE` | `JSON_EXTRACT` | `JSON_EXTRACT_PATH` | `UPPER` | `LOWER` | `COALESCE` | `CONCAT` | `LENGTH` | `ORDER_INDEX`;
export type FunctionCall<TContext extends Context = Context> = {
    [K in AllowedFunctionName]: {
        [key in K]: ConditionOperand<TContext> | Array<ConditionOperand<TContext>>;
    };
}[AllowedFunctionName];
export type AggregateFunctionName = `SUM` | `COUNT` | `AVG` | `MIN` | `MAX` | `MEDIAN` | `MODE`;
export type AggregateFunctionCall<TContext extends Context = Context> = {
    [K in AggregateFunctionName]: {
        [key in K]: ConditionOperand<TContext> | Array<ConditionOperand<TContext>>;
    };
}[AggregateFunctionName];
/**
 * An operand in a condition may be:
 * - A literal value (LiteralValue)
 * - A column reference (a string starting with "@" or an explicit { col: string } object)
 * - An explicit literal (to wrap arbitrary JSON or Date values) as { value: ... }
 * - A function call (as defined above)
 * - An array of operands (for example, for "in" clauses)
 */
export type ConditionOperand<TContext extends Context = Context, T extends any = any> = LiteralValue | PropertyReference<TContext> | ExplicitLiteral | FunctionCall<TContext> | Array<ConditionOperand<TContext, T>>;
export type Comparator = `=` | `!=` | `<` | `<=` | `>` | `>=` | `like` | `not like` | `in` | `not in` | `is` | `is not`;
export type LogicalOperator = `and` | `or`;
export type SimpleCondition<TContext extends Context = Context, T extends any = any> = [ConditionOperand<TContext, T>, Comparator, ConditionOperand<TContext, T>];
export type FlatCompositeCondition<TContext extends Context = Context, T extends any = any> = [
    ConditionOperand<TContext, T>,
    Comparator,
    ConditionOperand<TContext, T>,
    ...Array<LogicalOperator | ConditionOperand<TContext, T> | Comparator>
];
export type NestedCompositeCondition<TContext extends Context = Context, T extends any = any> = [
    SimpleCondition<TContext, T> | FlatCompositeCondition<TContext, T>,
    ...Array<LogicalOperator | SimpleCondition<TContext, T> | FlatCompositeCondition<TContext, T>>
];
export type Condition<TContext extends Context = Context, T extends any = any> = SimpleCondition<TContext, T> | FlatCompositeCondition<TContext, T> | NestedCompositeCondition<TContext, T>;
export interface JoinClause<TContext extends Context = Context> {
    type: `inner` | `left` | `right` | `full` | `cross`;
    from: string;
    as?: string;
    on: Condition<TContext>;
}
export type OrderBy<TContext extends Context = Context> = PropertyReferenceString<TContext> | {
    [column in PropertyReferenceString<TContext>]?: `asc` | `desc`;
} | Record<PropertyReferenceString<TContext>, `asc` | `desc`> | Array<PropertyReferenceString<TContext> | {
    [column in PropertyReferenceString<TContext>]?: `asc` | `desc`;
}>;
export type Select<TContext extends Context = Context> = PropertyReferenceString<TContext> | {
    [alias: string]: PropertyReference<TContext> | FunctionCall<TContext> | AggregateFunctionCall<TContext>;
} | WildcardReferenceString<TContext> | SelectCallback<TContext>;
export type SelectCallback<TContext extends Context = Context> = (context: TContext extends {
    schema: infer S;
} ? S : any) => any;
export type As<_TContext extends Context = Context> = string;
export type From<TContext extends Context = Context> = InputReference<{
    baseSchema: TContext[`baseSchema`];
    schema: TContext[`baseSchema`];
}>;
export type WhereCallback<TContext extends Context = Context> = (context: TContext extends {
    schema: infer S;
} ? S : any) => boolean;
export type Where<TContext extends Context = Context> = Array<Condition<TContext> | WhereCallback<TContext>>;
export type Having<TContext extends Context = Context> = Where<TContext>;
export type GroupBy<TContext extends Context = Context> = PropertyReference<TContext> | Array<PropertyReference<TContext>>;
export type Limit<_TContext extends Context = Context> = number;
export type Offset<_TContext extends Context = Context> = number;
export interface BaseQuery<TContext extends Context = Context> {
    select?: Array<Select<TContext>>;
    as?: As<TContext>;
    from: From<TContext>;
    join?: Array<JoinClause<TContext>>;
    where?: Where<TContext>;
    groupBy?: GroupBy<TContext>;
    having?: Having<TContext>;
    orderBy?: OrderBy<TContext>;
    limit?: Limit<TContext>;
    offset?: Offset<TContext>;
}
export interface Query<TContext extends Context = Context> extends BaseQuery<TContext> {
    with?: Array<WithQuery<TContext>>;
    collections?: {
        [K: string]: Collection<any>;
    };
}
export interface WithQuery<TContext extends Context = Context> extends BaseQuery<TContext> {
    as: string;
}
