import type { TgpuTexture } from '../core/texture/texture.ts';
import type { Disarray, Undecorate } from '../data/dataTypes.ts';
import type { WgslStorageTexture, WgslTexture } from '../data/texture.ts';
import type { U16, U32, WgslArray } from '../data/wgslTypes.ts';
import type { $gpuRepr, $gpuValueOf, $inRepr, $invalidSchemaReason, $memIdent, $repr, $reprPartial, $reprPatch, $validStorageSchema, $validUniformSchema, $validVertexSchema } from './symbols.ts';
import type { ViewDimensionToDimension } from '../core/texture/textureFormats.ts';
import type { Default } from './utilityTypes.ts';
/**
 * Extracts the inferred representation of a resource.
 * For inferring types as seen by the GPU, see {@link InferGPU}
 *
 * @example
 * type A = Infer<F32> // => number
 * type B = Infer<WgslArray<F32>> // => number[]
 * type C = Infer<Atomic<U32>> // => number
 */
export type Infer<T> = T extends {
    readonly [$repr]: infer TRepr;
} ? TRepr : T;
/**
 * Extracts the inferred input (write-side) representation of a resource.
 *
 * @example
 * type A = InferInput<Vec3f> // => v3f | [number, number, number] | Float32Array
 * type B = InferInput<WgslArray<Vec3f>> // => (v3f | [number, number, number] | Float32Array)[] | Float32Array
 * type C = InferInput<F32> // => number (same as Infer<F32>)
 * const arrayOfStructs = d.arrayOf(d.struct({ pos: d.vec3f, id: d.f32 }), 4);
 * type D = d.InferInput<typeof arrayOfStructs>; // { pos: d.v3f | Float32Array<ArrayBufferLike> | [number, number, number]; id: number; }[]
 */
export type InferInput<T> = Infer<T> | (T extends {
    readonly [$inRepr]: infer TRepr;
} ? TRepr : never);
/**
 * Extracts a sparse/partial inferred representation of a resource.
 * Used by the `buffer.writePartial` API.
 *
 * @deprecated
 *
 * @example
 * type A = InferPartial<F32> // => number | undefined
 * type B = InferPartial<WgslStruct<{ a: F32 }>> // => { a?: number | undefined }
 * type C = InferPartial<WgslArray<F32>> // => { idx: number; value: number | undefined }[] | undefined
 */
export type InferPartial<T> = T extends {
    readonly [$reprPartial]: infer TRepr;
} ? TRepr : T extends {
    readonly [$repr]: infer TRepr;
} ? TRepr | undefined : T;
/**
 * Extracts the inferred representation of a resource (as seen by the GPU).
 *
 * @example
 * type A = InferGPU<F32> // => number
 * type B = InferGPU<WgslArray<F32>> // => number[]
 * type C = InferGPU<Atomic<U32>> // => atomicU32
 */
export type InferGPU<T> = T extends {
    readonly [$gpuRepr]: infer TRepr;
} ? TRepr : Infer<T>;
export type InferRecord<T extends Record<string | number | symbol, unknown>> = {
    [Key in keyof T]: Infer<T[Key]>;
};
export type InferInputRecord<T extends Record<string | number | symbol, unknown>> = {
    [Key in keyof T]: InferInput<T[Key]>;
};
/** @deprecated */
export type InferPartialRecord<T extends Record<string | number | symbol, unknown>> = {
    [Key in keyof T]?: InferPartial<T[Key]>;
};
/**
 * Extracts the patch representation of a resource.
 * Used by the `buffer.patch` API.
 *
 * @example
 * type A = InferPatch<F32> // => number | undefined
 * type B = InferPatch<WgslStruct<{ a: F32 }>> // => { a?: number | undefined }
 * type C = InferPatch<WgslArray<F32>> // => Record<number, number | undefined> | number[] | undefined
 */
export type InferPatch<T> = T extends {
    readonly [$reprPatch]: infer TRepr;
} ? TRepr : InferInput<T> | undefined;
export type InferPatchRecord<T extends Record<string | number | symbol, unknown>> = {
    [Key in keyof T]?: InferPatch<T[Key]>;
};
export type InferGPURecord<T extends Record<string | number | symbol, unknown>> = {
    [Key in keyof T]: InferGPU<T[Key]>;
};
export type GPUValueOf<T> = T extends {
    readonly [$gpuValueOf]: infer TValue;
} ? TValue : T;
/**
 * Expands a schema to a union of other schemas that have the same binary representation.
 *
 * @example
 * type A = MemIdentity<F32> // => F32
 * type B = MemIdentity<I32> // => I32 | Atomic<I32> | Decorated<I32, Location[]>
 * type C = MemIdentity<WgslArray<I32>> // =>  WgslArray<I32 | Atomic<I32> | Decorated<I32, Location[]>>
 */
export type MemIdentity<T> = T extends {
    readonly [$memIdent]: infer TMemIdent;
} ? TMemIdent : T;
export type MemIdentityRecord<T extends Record<string | number | symbol, unknown>> = {
    [Key in keyof T]: MemIdentity<T[Key]>;
};
export type IsValidStorageSchema<T> = (T extends {
    readonly [$validStorageSchema]: true;
} ? true : false) extends false ? false : true;
export type IsValidUniformSchema<T> = (T extends {
    readonly [$validUniformSchema]: true;
} ? true : false) extends false ? false : true;
export type IsValidVertexSchema<T> = (T extends {
    readonly [$validVertexSchema]: true;
} ? true : false) extends false ? false : true;
/**
 * Accepts only arrays (or disarrays) of u32 or u16.
 */
export type IsValidIndexSchema<T> = Undecorate<T> extends WgslArray | Disarray ? Undecorate<Undecorate<T>['elementType']> extends U32 | U16 ? true : false : false;
/**
 * Checks if a schema can be used in a buffer at all
 */
export type IsValidBufferSchema<T> = IsValidStorageSchema<T> | IsValidUniformSchema<T> | IsValidVertexSchema<T> | IsValidIndexSchema<T> extends false ? false : true;
/**
 * Validates if a texture can be used as sampled texture
 */
export type IsValidSampledTextureUsage<TTexture extends TgpuTexture> = TTexture['usableAsSampled'] extends true ? true : {
    readonly invalidSampled: "Texture not usable as sampled, call $usage('sampled') first";
};
/**
 * Validates if a texture can be used as storage texture
 */
export type IsValidStorageTextureUsage<TTexture extends TgpuTexture> = TTexture['usableAsStorage'] extends true ? true : {
    readonly invalidStorage: "Texture not usable as storage, call $usage('storage') first";
};
/**
 * Validates if a texture view dimension is compatible with the texture dimension
 */
export type IsValidSubdimension<TTexture extends TgpuTexture, TSchema extends WgslTexture | WgslStorageTexture> = ViewDimensionToDimension[TSchema['dimension']] extends infer TVDim ? TVDim extends Default<TTexture['props']['dimension'], '2d'> ? true : {
    readonly invalidViewDim: `Texture dimension '${Default<TTexture['props']['dimension'], '2d'>}' incompatible with view dimension '${TSchema['dimension']}'`;
} : never;
export type IsValidStorageFormat<TTexture extends TgpuTexture, TSchema extends WgslStorageTexture> = TSchema['format'] extends TTexture['props']['format'] ? true : TTexture['props']['viewFormats'] extends readonly unknown[] ? TSchema['format'] extends TTexture['props']['viewFormats'][number] ? true : FormatError<TSchema, TTexture> : FormatError<TSchema, TTexture>;
type FormatError<TSchema extends WgslStorageTexture, TTexture extends TgpuTexture> = {
    readonly invalidFormat: `Storage texture format '${TSchema['format']}' incompatible with texture format '${TTexture['props']['format']}'`;
};
type IsExactly<T, U> = [T] extends [U] ? ([U] extends [T] ? true : false) : false;
type SelfOrErrors<TSelf, T> = IsExactly<T, true> extends true ? TSelf : `(Error) ${T[Extract<keyof T, `invalid${string}`>] & string}`;
export type ValidStorageUsage<TTexture extends TgpuTexture, TSchema extends WgslStorageTexture> = IsValidStorageTextureUsage<TTexture> & IsValidSubdimension<TTexture, TSchema> & IsValidStorageFormat<TTexture, TSchema>;
export type ValidSampledUsage<TTexture extends TgpuTexture, TSchema extends WgslTexture> = IsValidSampledTextureUsage<TTexture> & IsValidSubdimension<TTexture, TSchema>;
/**
 * Validates texture view schema against texture usage
 */
export type ValidateTextureViewSchema<TTexture extends TgpuTexture, TSchema extends WgslTexture | WgslStorageTexture> = TSchema extends WgslStorageTexture ? SelfOrErrors<TSchema, ValidStorageUsage<TTexture, TSchema>> : TSchema extends WgslTexture ? SelfOrErrors<TSchema, ValidSampledUsage<TTexture, TSchema>> : never;
export type ExtractInvalidSchemaError<T, TPrefix extends string = ''> = [T] extends [
    {
        readonly [$invalidSchemaReason]: string;
    }
] ? `${TPrefix}${T[typeof $invalidSchemaReason]}` : never;
export {};
