import { AnyDB } from "../databases";
import type { AnyValueSource, IValueSource, OptionalType, OptionalTypeRequiredOrAny, RemapIValueSourceTypeWithOptionalType, ValueSourceOf, ValueSourceValueTypeForRequiredInOptionalObject, ValueSourceValueTypeForObjectResult, ValueSourceValueTypeForOptionalObjectResultSameOuterJoin, ValueSourceValueTypeForNullableObjectResult, ValueSourceValueTypeForRequiredInNullableOptionalObject, ValueSourceValueTypeForOptionalNullableObjectResultSameOuterJoin } from "../expressions/values";
import { NoTableOrViewRequired, OUTER_JOIN_SOURCE, ITableOrViewRef } from "./ITableOrView";
import { database } from "./symbols";
export type ResultObjectValues<COLUMNS> = FixOptionalProperties<{
    [P in keyof COLUMNS]: COLUMNS[P] extends AnyValueSource | undefined ? ValueSourceValueTypeForObjectResult<NonNullable<COLUMNS[P]>> : InnerResultObjectValues<NonNullable<COLUMNS[P]>>;
}>;
export type ResultObjectValuesProjectedAsNullable<COLUMNS> = FixOptionalPropertiesProjectedAsNullable<{
    [P in keyof COLUMNS]: COLUMNS[P] extends AnyValueSource | undefined ? ValueSourceValueTypeForNullableObjectResult<NonNullable<COLUMNS[P]>> : InnerResultNullableObjectValues<NonNullable<COLUMNS[P]>>;
}>;
export type RequiredColumnNames<T> = T extends AnyValueSource ? 'result' : 'any' extends T ? never : RequiredInnerColumnNames<T, ''>;
type RequiredInnerColumnNames<T, PREFIX extends string> = {
    [K in keyof T]-?: K extends string ? T[K] extends AnyValueSource | undefined ? ({} extends Pick<T, K> ? never : `${PREFIX}${K}`) : RequiredInnerColumnNames<T[K], `${PREFIX}${K}.`> : never;
}[keyof T];
export type RequiredKeysOfPickingColumns<T> = T extends AnyValueSource ? never : {
    [K in keyof T]-?: {} extends Pick<T, K> ? never : K;
}[keyof T];
export type ColumnGuard<T> = T extends null | undefined ? never : [T] extends [never] ? never : T extends AnyValueSource ? never : unknown;
export type GuidedObj<T> = T & {
    [K in keyof T as K extends string | number ? `${K}!` : never]-?: NonNullable<T[K]>;
} & {
    [K in keyof T as K extends string | number ? `${K}?` : never]?: T[K];
};
export type GuidedPropName<T> = T extends `${infer Q}!` ? Q : T extends `${infer Q}?` ? Q : T;
export type ValueOf<T> = T[keyof T];
type FixPickableObjectWhereCouldBeNotPicked<RESULT> = undefined extends string ? RESULT : {} extends RESULT ? RESULT | undefined : RESULT;
export type FixOptionalProperties<RESULT> = undefined extends string ? RESULT : {
    [P in keyof OptionalMap<RESULT>]: true extends OptionalMap<RESULT> ? RESULT[P] : NonNullable<RESULT[P]>;
};
type OptionalMap<TYPE> = {
    [P in MandatoryPropertiesOf<TYPE>]-?: true;
} & {
    [P in OptionalPropertiesOf<TYPE>]?: false;
};
export type MandatoryPropertiesOf<TYPE> = Exclude<keyof TYPE, OptionalPropertiesOf<TYPE>>;
export type OptionalPropertiesOf<TYPE> = ({
    [K in keyof TYPE]-?: null | undefined extends TYPE[K] ? K : (null extends TYPE[K] ? K : (undefined extends TYPE[K] ? K : never));
})[keyof TYPE];
type FixPickableObjectWhereCouldBeNotPickedProjectedAsNullable<RESULT> = undefined extends string ? RESULT : {} extends RESULT ? RESULT | undefined | (true extends ContainsNullableProperties<RESULT> ? null : never) : {} extends FixOptionalProperties<RESULT> ? RESULT | null : RESULT;
type FixOptionalPropertiesProjectedAsNullable<RESULT> = undefined extends string ? RESULT : {
    [P in keyof OptionalMapProjectedAsNullable<RESULT>]: RESULT[P];
};
type OptionalMapProjectedAsNullable<TYPE> = {
    [P in AlwaysRequestedPropertiesOfProjectedAsNullable<TYPE>]-?: true;
} & {
    [P in OmittablePropertiesOfProjectedAsNullable<TYPE>]?: false;
};
type AlwaysRequestedPropertiesOfProjectedAsNullable<TYPE> = Exclude<keyof TYPE, OmittablePropertiesOfProjectedAsNullable<TYPE>>;
type OmittablePropertiesOfProjectedAsNullable<TYPE> = ({
    [K in keyof TYPE]-?: undefined extends TYPE[K] ? K : never;
})[keyof TYPE];
export type ColumnsForCompound<TABLE_OR_VIEW extends ITableOrViewRef<AnyDB>, COLUMNS> = COLUMNS extends AnyValueSource ? RemapIValueSourceTypeWithOptionalType<TABLE_OR_VIEW, COLUMNS, CompoundColumnOptionalType<COLUMNS>> : InnerColumnsForCompound<TABLE_OR_VIEW, COLUMNS>;
type InnerColumnsForCompound<TABLE_OR_VIEW extends ITableOrViewRef<AnyDB>, COLUMNS> = {
    [K in keyof COLUMNS]: COLUMNS[K] extends AnyValueSource | undefined ? RemapIValueSourceTypeWithOptionalType<TABLE_OR_VIEW, COLUMNS[K], CompoundColumnOptionalType<COLUMNS[K]>> : InnerColumnsForCompound<TABLE_OR_VIEW, COLUMNS[K]>;
};
type CompoundColumnOptionalType<COLUMN> = COLUMN extends IValueSource<any, any, any, infer OPTIONAL_TYPE> ? OptionalTypeRequiredOrAny<OPTIONAL_TYPE> : never;
type InnerResultObjectValues<COLUMNS> = FixPickableObjectWhereCouldBeNotPicked<ContainsRequiredInOptionalObject<COLUMNS> extends true ? FixOptionalProperties<{
    [P in keyof COLUMNS]: COLUMNS[P] extends AnyValueSource | undefined ? ValueSourceValueTypeForRequiredInOptionalObject<NonNullable<COLUMNS[P]>> : InnerResultObjectValues<NonNullable<COLUMNS[P]>>;
}> | undefined : AllFromSameLeftJoinWithOriginallyRequired<COLUMNS> extends true ? FixOptionalProperties<{
    [P in keyof COLUMNS]: COLUMNS[P] extends AnyValueSource | undefined ? ValueSourceValueTypeForOptionalObjectResultSameOuterJoin<NonNullable<COLUMNS[P]>> : InnerResultObjectValues<NonNullable<COLUMNS[P]>>;
}> | undefined : ContainsRequired<COLUMNS> extends true ? FixOptionalProperties<{
    [P in keyof COLUMNS]: COLUMNS[P] extends AnyValueSource | undefined ? ValueSourceValueTypeForObjectResult<NonNullable<COLUMNS[P]>> : InnerResultObjectValues<NonNullable<COLUMNS[P]>>;
}> : FixOptionalProperties<{
    [P in keyof COLUMNS]: COLUMNS[P] extends AnyValueSource | undefined ? ValueSourceValueTypeForObjectResult<NonNullable<COLUMNS[P]>> : InnerResultObjectValues<NonNullable<COLUMNS[P]>>;
}> | undefined>;
type InnerResultNullableObjectValues<COLUMNS> = FixPickableObjectWhereCouldBeNotPickedProjectedAsNullable<ContainsRequiredInOptionalObject<COLUMNS> extends true ? FixOptionalPropertiesProjectedAsNullable<{
    [P in keyof COLUMNS]: COLUMNS[P] extends AnyValueSource | undefined ? ValueSourceValueTypeForRequiredInNullableOptionalObject<NonNullable<COLUMNS[P]>> : InnerResultNullableObjectValues<NonNullable<COLUMNS[P]>>;
}> | null : AllFromSameLeftJoinWithOriginallyRequired<COLUMNS> extends true ? FixOptionalPropertiesProjectedAsNullable<{
    [P in keyof COLUMNS]: COLUMNS[P] extends AnyValueSource | undefined ? ValueSourceValueTypeForOptionalNullableObjectResultSameOuterJoin<NonNullable<COLUMNS[P]>> : InnerResultNullableObjectValues<NonNullable<COLUMNS[P]>>;
}> | null : ContainsRequired<COLUMNS> extends true ? FixOptionalPropertiesProjectedAsNullable<{
    [P in keyof COLUMNS]: COLUMNS[P] extends AnyValueSource | undefined ? ValueSourceValueTypeForNullableObjectResult<NonNullable<COLUMNS[P]>> : InnerResultNullableObjectValues<NonNullable<COLUMNS[P]>>;
}> : FixOptionalPropertiesProjectedAsNullable<{
    [P in keyof COLUMNS]: COLUMNS[P] extends AnyValueSource | undefined ? ValueSourceValueTypeForNullableObjectResult<NonNullable<COLUMNS[P]>> : InnerResultNullableObjectValues<NonNullable<COLUMNS[P]>>;
}> | null>;
export type InnerResultObjectValuesForAggregatedArray<COLUMNS> = NonNullable<InnerResultObjectValues<COLUMNS>>;
export type InnerResultNullableObjectValuesForAggregatedArray<COLUMNS> = NonNullable<InnerResultNullableObjectValues<COLUMNS>>;
type ContainsRequiredInOptionalObject<TYPE> = FalseWhenNever<({
    [K in keyof TYPE]-?: TYPE[K] extends IValueSource<any, any, any, infer OPTIONAL_TYPE> | undefined ? IsRequiredInOptionalObject<OPTIONAL_TYPE> : never;
})[keyof TYPE]>;
type ContainsRequired<TYPE> = FalseWhenNever<({
    [K in keyof TYPE]-?: TYPE[K] extends IValueSource<any, any, any, infer OPTIONAL_TYPE> | undefined ? IsRequired<OPTIONAL_TYPE> : InnerObjectIsRequired<TYPE[K]> extends true ? true : never;
})[keyof TYPE]>;
type InnerObjectIsRequired<TYPE> = ContainsRequiredInOptionalObject<TYPE> extends true ? false : AllFromSameLeftJoinWithOriginallyRequired<TYPE> extends true ? false : ContainsRequired<TYPE>;
type AllFromSameLeftJoinWithOriginallyRequired<TYPE> = FalseWhenNever<({
    [K in keyof TYPE]-?: TYPE[K] extends IValueSource<infer T, any, any, infer OPTIONAL_TYPE> | undefined ? OUTER_JOIN_SOURCE<any, any> extends T ? (InnerTables<TYPE> | NoTableOrViewRequired<T[typeof database]> extends T | NoTableOrViewRequired<T[typeof database]> ? IsOriginallyRequired<OPTIONAL_TYPE> : false) : T extends NoTableOrViewRequired<T[typeof database]> ? never : false : never;
})[keyof TYPE]>;
type InnerTables<TYPE> = ({
    [K in keyof TYPE]-?: TYPE[K] extends ValueSourceOf<infer T> | undefined ? T : never;
})[keyof TYPE];
type IsRequiredInOptionalObject<OPTIONAL_TYPE extends OptionalType> = 'any' extends OPTIONAL_TYPE ? never : 'requiredInOptionalObject' extends OPTIONAL_TYPE ? true : never;
type IsOriginallyRequired<OPTIONAL_TYPE extends OptionalType> = 'any' extends OPTIONAL_TYPE ? never : 'originallyRequired' extends OPTIONAL_TYPE ? true : never;
type IsRequired<OPTIONAL_TYPE extends OptionalType> = 'any' extends OPTIONAL_TYPE ? never : 'required' extends OPTIONAL_TYPE ? true : never;
type ContainsNullableProperties<T> = FalseWhenNever<{
    [P in keyof T]-?: null extends T[P] ? true : never;
}[keyof T]>;
type FalseWhenNever<T> = [T] extends [never] ? false : T;
export {};
/**
 * Alternative solution that allows to expose the inner objects in the with, but typescript get frozen
 * This implementation doesn't deal when a inner property is used alone. See the case when in this view the inner property
 * is requiredInOptionalObject but that property is used in a way that flag make no sence any more
 */
