import { JSONSchema, FromSchema as FromSchema$1 } from 'json-schema-to-ts';
import zod from 'zod';

/**
 * A minimal JSON schema type.
 *
 * This type is used to narrow the type of a JSON schema to a minimal type
 * that is compatible with the `json-schema-to-ts` library.
 */
type JsonSchemaMinimal = {
    type: 'object';
} | {
    anyOf: unknown[];
} | {
    allOf: unknown[];
} | {
    oneOf: unknown[];
};
/**
 * A JSON schema
 */
type JsonSchema = Exclude<JSONSchema, boolean> & JsonSchemaMinimal;
/**
 * Infer the data type of a JsonSchema.
 *
 * @param T - The `JsonSchema` to infer the data type of.
 * @param Options - Configuration options for the type inference. The `validated` flag determines whether the schema has been validated. If `validated` is true, all properties are required unless specified otherwise. If false, properties with default values are optional.
 *
 * @returns The inferred type.
 *
 * @example
 * ```ts
 * const mySchema = {
 *   type: 'object',
 *   properties: {
 *     name: { type: 'string' },
 *     email: { type: 'string' },
 *   },
 *   required: ['name'],
 *   additionalProperties: false,
 * } as const satisfies JsonSchema;
 *
 * // has type { name: string, email?: string }
 * type MySchema = InferJsonSchema<typeof mySchema, { validated: true }>;
 * ```
 */
type InferJsonSchema<T, Options extends {
    validated: boolean;
}> = T extends JsonSchemaMinimal ? T extends JSONSchema ? Options['validated'] extends true ? FromSchema$1<T> : FromSchema$1<T, {
    keepDefaultedPropertiesOptional: true;
}> : never : never;

/**
 * A ZodSchema used to validate a JSON object.
 */
type ZodSchema = zod.ZodType<Record<string, unknown>, zod.ZodTypeDef, Record<string, unknown>>;
/**
 * A minimal ZodSchema type.
 *
 * It is necessary to define a minimal ZodSchema type to enable correct inference
 * when Zod is not available, as Typescript doesn't support detection of module
 * availability via `typeof import('zod')`.
 */
type ZodSchemaMinimal = {
    readonly safeParseAsync: unknown;
};
/**
 * Infer the data type of a ZodSchema.
 *
 * @param T - The ZodSchema to infer the data type of.
 * @param Options - Configuration options for the type inference. The `validated` flag determines whether the schema has been validated. If `validated` is true, all properties are required unless specified otherwise. If false, properties with default values are optional.
 *
 * @example
 * ```ts
 * const mySchema = z.object({
 *   name: z.string(),
 *   email: z.string().optional(),
 * });
 *
 * // has type { name: string, email?: string }
 * type MySchema = InferZodSchema<typeof mySchema>;
 * ```
 */
type InferZodSchema<T, Options extends {
    validated: boolean;
}> = T extends ZodSchemaMinimal ? T extends {
    readonly _output: infer Output extends Record<string, unknown>;
    readonly _input: infer Input extends Record<string, unknown>;
} ? Options['validated'] extends true ? Output : Input : never : never;

/**
 * A schema used to validate a JSON object.
 */
type Schema = JsonSchemaMinimal | ZodSchemaMinimal;
/**
 * Main utility type for schema inference
 *
 * @param T - The Schema to infer the type of.
 * @param Options - Configuration options for the type inference. The `validated` flag determines whether the schema has been validated. If `validated` is true, all properties are required unless specified otherwise. If false, properties with default values are optional.
 */
type InferSchema<T extends Schema, Options extends {
    validated: boolean;
}> = InferJsonSchema<T, Options> | InferZodSchema<T, Options>;
/**
 * Infer the type of a Schema for unvalidated data.
 *
 * The resulting type has default properties set to optional,
 * reflecting the fact that the data is unvalidated and has
 * not had default properties set.
 *
 * @example
 * ```ts
 * type MySchema = FromSchemaUnvalidated<typeof mySchema>;
 * ```
 */
type FromSchemaUnvalidated<T extends Schema> = InferSchema<T, {
    validated: false;
}>;
/**
 * Infer the type of a Schema for validated data.
 *
 * The resulting type has default properties set to required,
 * reflecting the fact that the data has been validated and
 * default properties have been set.
 *
 * @example
 * ```ts
 * type MySchema = FromSchema<typeof mySchema>;
 * ```
 */
type FromSchema<T extends Schema> = InferSchema<T, {
    validated: true;
}>;

export type { FromSchemaUnvalidated as F, JsonSchema as J, Schema as S, ZodSchema as Z, FromSchema as a, ZodSchemaMinimal as b };
