import { type Bind, type Kind3, type TypeLambda } from 'sts:hkt';
import { Failure } from 'sts:failures';
import { type Option, type Result } from 'sts:result';
import type { Contravariant } from 'sts:typeclasses';
import type { UrlLike } from 'sts:decode';
import { type JsonArray, type JsonObject, type JsonValue } from './json';
export type EncodeMode = 'sync' | 'async';
export type ObjectKeyPolicy = 'strip' | 'strict' | 'passthrough';
export type EncodeObjectOptions = {
    readonly unknownKeys?: ObjectKeyPolicy;
};
export type EncodePathSegment = string | number;
export type EncodePath = readonly EncodePathSegment[];
export type EncodeIssue = {
    readonly code: string;
    readonly input?: unknown;
    readonly message: string;
    readonly path: EncodePath;
};
export type EncodeRefinementContext = {
    readonly path: EncodePath;
    // #[effects(add: [])]
    issue(code: string, message: string, input?: unknown): EncodeIssue;
};
export type EncodeRefinementResult = boolean | string | EncodeIssue | readonly EncodeIssue[];
export type EncodeOutput<T, E, M extends EncodeMode = 'sync'> = M extends 'async' ? Promise<Result<T, E>> : Result<T, E>;
type MaybeEncodeOutput<T, E> = Result<T, E> | Promise<Result<T, E>>;
type AsyncModeOf<TReturn> = TReturn extends Promise<unknown> ? 'async' : 'sync';
type EncodeState = {
    readonly seen: WeakSet<object>;
};
export declare class EncodeFailure extends Failure {
    readonly path: EncodePath;
    // #[effects(add: [mut])]
    constructor(message?: string, options?: Readonly<{
        cause?: unknown;
        path?: EncodePath;
    }>);
    // #[effects(add: [], unknown: [direct])]
    at(segment: EncodePathSegment): this;
}
export type Encoder<T, TEncoded = unknown, E = EncodeFailure, M extends EncodeMode = 'sync'> = {
    // #[effects(add: [suspend.await], unknown: [direct])]
    encode(value: T): EncodeOutput<TEncoded, E, M>;
    // #[effects(add: [], unknown: [direct])]
    validateEncode(value: T): EncodeOutput<TEncoded, readonly EncodeIssue[], M>;
};
export type OptionalEncoder<T, TEncoded = T, E = EncodeFailure, M extends EncodeMode = 'sync'> = Encoder<T | undefined, TEncoded | undefined, E, M> & {
    readonly __soundscriptOptional: true;
    readonly inner: Encoder<T, TEncoded, E, M>;
};
type EncoderInput<TEncoder> = TEncoder extends Encoder<infer T, unknown, unknown, EncodeMode> ? T : never;
type EncoderOutputValue<TEncoder> = TEncoder extends Encoder<unknown, infer TEncoded, unknown, EncodeMode> ? TEncoded : never;
type EncoderError<TEncoder> = TEncoder extends Encoder<unknown, unknown, infer E, EncodeMode> ? E : never;
type EncoderModeOf<TEncoder> = TEncoder extends Encoder<unknown, unknown, unknown, infer M> ? M : never;
type MergeEncodeModes<M extends EncodeMode> = [
    M
] extends [
    never
] ? 'sync' : 'async' extends M ? 'async' : 'sync';
type ObjectShape = Record<string, Encoder<unknown, unknown, unknown, EncodeMode>>;
type TupleShape = readonly Encoder<unknown, unknown, unknown, EncodeMode>[];
type OptionalShapeKeys<TShape extends ObjectShape> = {
    readonly [K in keyof TShape]-?: TShape[K] extends OptionalEncoder<unknown, unknown, unknown, EncodeMode> ? K : never;
}[keyof TShape];
type RequiredShapeKeys<TShape extends ObjectShape> = Exclude<keyof TShape, OptionalShapeKeys<TShape>>;
type ObjectInputOfShape<TShape extends ObjectShape> = {
    readonly [K in RequiredShapeKeys<TShape>]: EncoderInput<TShape[K]>;
} & {
    readonly [K in OptionalShapeKeys<TShape>]?: Exclude<EncoderInput<TShape[K]>, undefined>;
};
type ObjectOutputOfShape<TShape extends ObjectShape> = {
    readonly [K in RequiredShapeKeys<TShape>]: EncoderOutputValue<TShape[K]>;
} & {
    readonly [K in OptionalShapeKeys<TShape>]?: Exclude<EncoderOutputValue<TShape[K]>, undefined>;
};
type ShapeEncodeMode<TShape extends ObjectShape> = true extends {
    readonly [K in keyof TShape]: EncoderModeOf<TShape[K]> extends 'async' ? true : false;
}[keyof TShape] ? 'async' : 'sync';
type TupleEncodeMode<TElements extends TupleShape> = true extends {
    readonly [K in keyof TElements]: TElements[K] extends Encoder<unknown, unknown, unknown, 'async'> ? true : false;
}[number] ? 'async' : 'sync';
export interface EncoderF extends TypeLambda {
    readonly type: Encoder<this['Args'][2], this['Args'][1], this['Args'][0]>;
}
export type EncoderKind<E, TEncoded, T> = Kind3<EncoderF, E, TEncoded, T>;
// #[effects(add: [mut], forward: [{ from: encode.some }])]
export declare function fromEncode<T, TEncoded, E, M extends EncodeMode = 'sync'>(encode: (value: T, state?: EncodeState) => MaybeEncodeOutput<TEncoded, E>, validateEncode?: (value: T, state?: EncodeState) => MaybeEncodeOutput<TEncoded, readonly EncodeIssue[]>): Encoder<T, TEncoded, E, M>;
// #[effects(add: [mut], unknown: [direct])]
export declare function contramap<TEncoder extends Encoder<unknown, unknown, unknown, EncodeMode>, B>(encoder: TEncoder, project: (value: B) => EncoderInput<TEncoder>): Encoder<B, EncoderOutputValue<TEncoder>, EncoderError<TEncoder>, EncoderModeOf<TEncoder>>;
// #[effects(add: [mut], unknown: [direct])]
export declare function contramap<TEncoder extends Encoder<unknown, unknown, unknown, EncodeMode>, B, TProjected extends EncoderInput<TEncoder> | Promise<EncoderInput<TEncoder>>>(encoder: TEncoder, project: (value: B) => TProjected): Encoder<B, EncoderOutputValue<TEncoder>, EncoderError<TEncoder>, MergeEncodeModes<EncoderModeOf<TEncoder> | AsyncModeOf<TProjected>>>;
// #[effects(add: [])]
export declare function encoderContravariant<TEncoded, E = EncodeFailure>(): Contravariant<Bind<Bind<EncoderF, [
    E
]>, [
    TEncoded
]>>;
export declare const stringEncoder: Encoder<string, string>;
export declare const numberEncoder: Encoder<number, number>;
export declare const booleanEncoder: Encoder<boolean, boolean>;
export declare const bigintEncoder: Encoder<bigint, bigint>;
export declare const undefinedEncoder: Encoder<undefined, undefined>;
export declare const url: Encoder<UrlLike, string>;
export declare const isoDate: Encoder<Date, string>;
export declare const jsonValue: Encoder<JsonValue, JsonValue>;
export declare const jsonObject: Encoder<JsonObject, JsonObject>;
export declare const jsonArray: Encoder<JsonArray, JsonArray>;
// #[effects(add: [mut], unknown: [direct])]
export declare function mapError<T, TEncoded, E1, E2, M extends EncodeMode>(encoder: Encoder<T, TEncoded, E1, M>, project: (error: E1) => E2): Encoder<T, TEncoded, E2, M>;
// #[effects(add: [mut], unknown: [direct])]
export declare function refine<T, TEncoded, E, M extends EncodeMode>(encoder: Encoder<T, TEncoded, E, M>, predicate: (value: T, ctx: EncodeRefinementContext) => value is T, message: string): Encoder<T, TEncoded, E | EncodeFailure, M>;
// #[effects(add: [mut], unknown: [direct])]
export declare function refine<T, TEncoded, E, M extends EncodeMode, TResult extends EncodeRefinementResult | Promise<EncodeRefinementResult>>(encoder: Encoder<T, TEncoded, E, M>, predicate: (value: T, ctx: EncodeRefinementContext) => TResult, message: string): Encoder<T, TEncoded, E | EncodeFailure, MergeEncodeModes<M | AsyncModeOf<TResult>>>;
// #[effects(add: [mut], unknown: [direct])]
export declare function optional<TEncoder extends Encoder<unknown, unknown, unknown, EncodeMode>>(encoder: TEncoder): OptionalEncoder<Exclude<EncoderInput<TEncoder>, undefined>, Exclude<EncoderOutputValue<TEncoder>, undefined>, EncoderError<TEncoder>, EncoderModeOf<TEncoder>>;
// #[effects(add: [mut], unknown: [direct])]
export declare function optional<T, TEncoded, E, M extends EncodeMode>(encoder: Encoder<T, TEncoded, E, M>): OptionalEncoder<Exclude<T, undefined>, Exclude<TEncoded, undefined>, E, M>;
// #[effects(add: [mut], unknown: [direct])]
export declare function undefinedable<T, TEncoded, E, M extends EncodeMode>(encoder: Encoder<T, TEncoded, E, M>): Encoder<T | undefined, TEncoded | undefined, E, M>;
// #[effects(add: [mut], unknown: [direct])]
export declare function lazy<TEncoder extends Encoder<unknown, unknown, unknown, EncodeMode>>(getEncoder: () => TEncoder): Encoder<EncoderInput<TEncoder>, EncoderOutputValue<TEncoder>, EncoderError<TEncoder>, EncoderModeOf<TEncoder>>;
// #[effects(add: [mut], unknown: [direct])]
export declare function nullable<T, TEncoded, E, M extends EncodeMode>(encoder: Encoder<T, TEncoded, E, M>): Encoder<T | null, TEncoded | null, E, M>;
// #[effects(add: [mut], unknown: [direct])]
export declare function literal<const T extends string | number | boolean | null>(value: T): Encoder<T, T>;
// #[effects(add: [mut], unknown: [direct])]
export declare function array<T, TEncoded, E>(item: Encoder<T, TEncoded, E, 'sync'>): Encoder<readonly T[], readonly TEncoded[], E | EncodeFailure, 'sync'>;
// #[effects(add: [mut], unknown: [direct])]
export declare function array<T, TEncoded, E>(item: Encoder<T, TEncoded, E, 'async'>): Encoder<readonly T[], readonly TEncoded[], E | EncodeFailure, 'async'>;
// #[effects(add: [mut], unknown: [direct])]
export declare function record<T, TEncoded, E, M extends EncodeMode>(valueEncoder: Encoder<T, TEncoded, E, M>): Encoder<Readonly<Record<string, T>>, Readonly<Record<string, TEncoded>>, E | EncodeFailure, M>;
// #[effects(add: [mut], unknown: [direct])]
export declare function tuple<const TElements extends TupleShape>(...elements: TElements): Encoder<{
    readonly [K in keyof TElements]: EncoderInput<TElements[K]>;
}, {
    readonly [K in keyof TElements]: EncoderOutputValue<TElements[K]>;
}, EncoderError<TElements[number]>, TupleEncodeMode<TElements>>;
// #[effects(add: [mut], unknown: [direct])]
export declare function option<T, TEncoded, E, M extends EncodeMode>(item: Encoder<T, TEncoded, E, M>): Encoder<Option<T>, {
    readonly tag: 'none';
} | {
    readonly tag: 'some';
    readonly value: TEncoded;
}, E, M>;
// #[effects(add: [mut], unknown: [direct])]
export declare function result<T, EValue, TEncoded, EEncoded, EOk, EErr, MOk extends EncodeMode, MErr extends EncodeMode>(okEncoder: Encoder<T, TEncoded, EOk, MOk>, errEncoder: Encoder<EValue, EEncoded, EErr, MErr>): Encoder<Result<T, EValue>, {
    readonly tag: 'ok';
    readonly value: TEncoded;
} | {
    readonly error: EEncoded;
    readonly tag: 'err';
}, EOk | EErr, MergeEncodeModes<MOk | MErr>>;
// #[effects(add: [mut], unknown: [direct])]
export declare function object<TShape extends ObjectShape>(shape: TShape, options?: EncodeObjectOptions): Encoder<ObjectInputOfShape<TShape>, ObjectOutputOfShape<TShape>, EncoderError<TShape[keyof TShape]> | EncodeFailure, ShapeEncodeMode<TShape>>;
// #[effects(add: [mut], unknown: [direct])]
export declare function strictObject<TShape extends ObjectShape>(shape: TShape): Encoder<ObjectInputOfShape<TShape>, ObjectOutputOfShape<TShape>, EncoderError<TShape[keyof TShape]> | EncodeFailure, ShapeEncodeMode<TShape>>;
// #[effects(add: [mut], unknown: [direct])]
export declare function passthroughObject<TShape extends ObjectShape>(shape: TShape): Encoder<ObjectInputOfShape<TShape>, ObjectOutputOfShape<TShape>, EncoderError<TShape[keyof TShape]> | EncodeFailure, ShapeEncodeMode<TShape>>;
export {};
