import { createIssue, failure, success, createParseMethods, SCHEMA_KIND } from "../base.js";
import { optional } from "../utils/optional.js";
import { nullable } from "../utils/nullable.js";
/**
 * Schema for validating objects with typed properties.
 * Validates each property according to its schema and collects all validation errors.
 *
 * @template T - The object shape definition
 *
 * @example
 * ```typescript
 * const userSchema = s.object({
 *   name: s.string(),
 *   age: s.number(),
 *   email: s.string()
 * });
 *
 * const user = userSchema.parse({
 *   name: 'John',
 *   age: 30,
 *   email: 'john@example.com'
 * });
 * ```
 */
export class ObjectSchema {
    shape;
    [SCHEMA_KIND] = 'ObjectSchema';
    description;
    parseMethods = createParseMethods();
    constructor(shape) {
        this.shape = shape;
    }
    '~standard' = {
        version: 1,
        vendor: 'agentuity',
        validate: (value) => {
            if (value === null) {
                return failure([createIssue('Expected object, got null')]);
            }
            if (Array.isArray(value)) {
                return failure([createIssue('Expected object, got array')]);
            }
            if (typeof value !== 'object') {
                return failure([createIssue(`Expected object, got ${typeof value}`)]);
            }
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            const result = {};
            const issues = [];
            for (const [key, schema] of Object.entries(this.shape)) {
                const fieldValue = value[key];
                const validation = schema['~standard'].validate(fieldValue);
                // Only support synchronous validation for now
                if (validation instanceof Promise) {
                    throw new Error('Async validation not supported');
                }
                if (validation.issues) {
                    for (const issue of validation.issues) {
                        issues.push(createIssue(issue.message, issue.path ? [key, ...issue.path] : [key]));
                    }
                }
                else {
                    result[key] = validation.value;
                }
            }
            if (issues.length > 0) {
                return failure(issues);
            }
            return success(result);
        },
        types: undefined,
    };
    describe(description) {
        this.description = description;
        return this;
    }
    optional() {
        return optional(this);
    }
    nullable() {
        return nullable(this);
    }
    /**
     * Create a new object schema with only the specified keys.
     * Similar to TypeScript's Pick<T, K> utility type.
     *
     * @param keys - Array of keys to pick from the schema
     *
     * @example
     * ```typescript
     * const userSchema = s.object({ name: s.string(), age: s.number(), email: s.string() });
     * const nameOnlySchema = userSchema.pick(['name']);
     * // { name: string }
     * ```
     */
    pick(keys) {
        const newShape = {};
        for (const key of keys) {
            if (key in this.shape) {
                newShape[key] = this.shape[key];
            }
        }
        return new ObjectSchema(newShape);
    }
    /**
     * Create a new object schema without the specified keys.
     * Similar to TypeScript's Omit<T, K> utility type.
     *
     * @param keys - Array of keys to omit from the schema
     *
     * @example
     * ```typescript
     * const userSchema = s.object({ name: s.string(), age: s.number(), password: s.string() });
     * const publicUserSchema = userSchema.omit(['password']);
     * // { name: string; age: number }
     * ```
     */
    omit(keys) {
        const keysSet = new Set(keys);
        const newShape = {};
        for (const [key, schema] of Object.entries(this.shape)) {
            if (!keysSet.has(key)) {
                newShape[key] = schema;
            }
        }
        return new ObjectSchema(newShape);
    }
    /**
     * Create a new object schema where all properties are optional.
     * Similar to TypeScript's Partial<T> utility type.
     *
     * @example
     * ```typescript
     * const userSchema = s.object({ name: s.string(), age: s.number() });
     * const partialUserSchema = userSchema.partial();
     * // { name?: string; age?: number }
     * ```
     */
    partial() {
        const newShape = {};
        for (const [key, schema] of Object.entries(this.shape)) {
            newShape[key] = optional(schema);
        }
        return new ObjectSchema(newShape);
    }
    /**
     * Create a new object schema by extending this schema with additional properties.
     * Properties in the extension override properties in the base schema.
     * Similar to TypeScript's intersection types with override semantics.
     *
     * @param extension - Object shape to extend with
     *
     * @example
     * ```typescript
     * const userSchema = s.object({ name: s.string(), age: s.number() });
     * const adminSchema = userSchema.extend({ role: s.literal('admin'), permissions: s.array(s.string()) });
     * // { name: string; age: number; role: 'admin'; permissions: string[] }
     * ```
     */
    extend(extension) {
        const newShape = { ...this.shape, ...extension };
        return new ObjectSchema(newShape);
    }
    parse = this.parseMethods.parse;
    safeParse = this.parseMethods.safeParse;
}
/**
 * Create an object schema with typed properties.
 *
 * @param shape - Object defining the schema for each property
 *
 * @example
 * ```typescript
 * const userSchema = s.object({
 *   name: s.string().describe('Full name'),
 *   age: s.number().describe('Age in years'),
 *   email: s.optional(s.string())
 * });
 *
 * type User = s.infer<typeof userSchema>;
 * const user = userSchema.parse(data);
 * ```
 */
export function object(shape) {
    return new ObjectSchema(shape);
}
//# sourceMappingURL=object.js.map