import type { Constructor, Except, IfNever, Simplify } from "type-fest";
import { type Decodable } from "./decoder.js";
import { type EncodableObj } from "./encoder.js";
import { EvDecoder } from "./ev-decoder.js";
import type { StructFieldType } from "./struct-field.js";
/** StructBuilder field options. */
interface Options<Required extends boolean, Repeat extends boolean, FlagPrefix extends string, FlagBit extends string> extends EvDecoder.RuleOptions {
    /**
     * Whether the field is required.
     * If both `.required` and `.repeat` are false, the field may be set to undefined and is initialized as undefined.
     * @defaultValue `false`
     */
    required?: Required;
    /**
     * Whether the field is repeated.
     * If `.repeat` is true, the field is defined as an array and is initialized as an empty array.
     * @defaultValue `false`
     */
    repeat?: Repeat;
    /**
     * Prefix of bit property names.
     * Ignored if `.flagBits` is unspecified.
     *
     * @defaultValue
     * Same as primary field name.
     */
    flagPrefix?: FlagPrefix;
    /**
     * Mapping from bit name to bit value.
     * If specified, the field is treated as bit flags.
     */
    flagBits?: Record<FlagBit, number>;
}
type ErrFlags = "ERROR: can only define flags on a non-repeatable number field";
type ValidateOptions<T, Repeat extends boolean, FlagBit extends string, R> = IfNever<FlagBit, R, Repeat extends true ? ErrFlags : T extends number ? R : ErrFlags>;
type AddField<K extends string, T, Required extends boolean, Repeat extends boolean> = Repeat extends true ? {
    [key in K]: T[];
} : Required extends true ? {
    [key in K]: T;
} : {
    [key in K]?: T;
};
type AddFlags<FlagPrefix extends string, FlagBit extends string> = {
    [key in `${FlagPrefix}${Capitalize<FlagBit>}`]: boolean;
};
/**
 * Helper to build a base class that represents a TLV structure.
 *
 * @remarks
 * StructBuilder allows you to define the typing, constructor, encoder, and decoder, while writing
 * each field only once. To be compatible with StructBuilder, the TLV structure being described
 * shall contain a sequence of sub-TLV elements with distinct TLV-TYPE numbers, where each
 * sub-TLV-TYPE appears zero, one, or multiple times.
 *
 * To use StructBuilder, calling code should follow these steps:
 * 1. Invoke `.add()` method successively to define sub-TLV elements.
 * 2. Obtain a base class via `.baseClass()` method, which contains one field for each sub-TLV-TYPE
 *    as defined, along with constructor, encoding, and decoding functions.
 * 3. Declare a subclass deriving from this base class, to add more functionality.
 * 4. Assign the subclass constructor to `.subclass` property of the builder.
 */
export declare class StructBuilder<U extends {}> {
    readonly typeName: string;
    readonly topTT?: number | undefined;
    /**
     * Constructor.
     * @param typeName - Type name, used in error messages.
     * @param topTT - If specified, encode as complete TLV; otherwise, encode as TLV-VALUE only.
     */
    constructor(typeName: string, topTT?: number | undefined);
    /**
     * Subclass constructor.
     * This must be assigned, otherwise decoding function will not work.
     */
    subclass?: Constructor<U, []> & Decodable<U>;
    private readonly fields;
    private readonly flagBits;
    private readonly EVD;
    /** Access EvDecoder for certain customizations. */
    static evdOf<U extends {}>(sb: StructBuilder<U>): Except<EvDecoder<U>, "add">;
    /** Retrieve field names. */
    static keysOf<U extends {}>(sb: StructBuilder<U>): Array<keyof U>;
    /**
     * Add a field.
     * @param tt - TLV-TYPE number.
     * @param key - Field name on the base class.
     * @param type - Field type.
     * @param opts - Field options.
     * @returns StructBuilder annotated with field typing.
     */
    add<T, K extends string, Required extends boolean = false, Repeat extends boolean = false, FlagPrefix extends string = K, FlagBit extends string = never>(tt: number, key: ValidateOptions<T, Repeat, FlagBit, K>, type: StructFieldType<T>, opts?: Options<Required, Repeat, FlagPrefix, FlagBit>): StructBuilder<Simplify<U & AddField<K, T, Required, Repeat> & AddFlags<FlagPrefix, FlagBit>>>;
    /** Change IsCritical on the EvDecoder. */
    setIsCritical(cb: EvDecoder.IsCritical): this;
    /**
     * Obtain a base class for the TLV structure class.
     * @typeParam S - Subclass type.
     */
    baseClass<S>(): (new () => Simplify<U> & EncodableObj) & Decodable<S>;
}
/**
 * Infer fields of a class built by StructBuilder.
 * @typeParam B - StructBuilder annotated with field typing.
 */
export type StructFields<B extends StructBuilder<{}>> = B extends StructBuilder<infer U> ? U : never;
export {};
