import type { Effect, Either } from 'effect';
/** Minimal Registry interface needed by TypeDeclaration.unify / .templated */
export interface IRegistryBase {
    getOptionalType(type: ITypeDeclaration): ITypeDeclaration;
    getListType(type: ITypeDeclaration): ITypeDeclaration;
    getMapType(a: ITypeDeclaration, b: ITypeDeclaration): ITypeDeclaration;
}
export interface IObjectTypeEntry {
    name: string;
    type: ITypeDeclaration;
    fields?: Record<string, ITypeDeclaration>;
    ctor?: unknown;
    convert?: ((v: unknown) => unknown) | undefined;
}
/** Minimal evaluator interface needed by registry.ts (avoids circular import operators→registry) */
export interface IEvaluatorBase {
    objectTypesByConstructor: Map<object, IObjectTypeEntry>;
    objectTypes: Map<string, IObjectTypeEntry>;
    debugType(v: unknown): ITypeDeclaration;
}
export interface ITypeDeclaration {
    kind: string;
    type: string;
    name: string;
    keyType: ITypeDeclaration | undefined;
    valueType: ITypeDeclaration | undefined;
    unwrappedType: ITypeDeclaration;
    wrappedType: ITypeDeclaration;
    hasDynType: boolean;
    hasPlaceholderType: boolean;
    matchesValueType: ((v: unknown, ev: IEvaluatorBase) => boolean) | undefined;
    fieldLazy: (obj: unknown, key: unknown, ast: IASTNode, ev: IEvaluatorBase) => unknown;
    isDynOrBool(): boolean;
    isEmpty(): boolean;
    unify(r: IRegistryBase, t2: ITypeDeclaration): ITypeDeclaration | null;
    templated(r: IRegistryBase, bind: Map<string, ITypeDeclaration> | null | undefined): ITypeDeclaration;
    field(obj: unknown, key: unknown, ast: IASTNode, ev: IEvaluatorBase): unknown;
    matches(o: ITypeDeclaration): boolean;
    matchesBoth(o: ITypeDeclaration): boolean;
    toString(): string;
}
export interface IOperatorMatch {
    handler: (...args: unknown[]) => unknown;
    returnType: ITypeDeclaration;
    async?: boolean;
    leftType?: ITypeDeclaration;
    rightType?: ITypeDeclaration;
    signature?: string;
}
export interface IFunctionMatch {
    handler: (...args: unknown[]) => unknown;
    returnType: ITypeDeclaration;
    async?: boolean;
    signature?: string;
}
export interface ICandidates {
    returnType: ITypeDeclaration | null;
    macro: unknown;
    findFunction(argTypes: ITypeDeclaration[], receiverType?: ITypeDeclaration | null): IFunctionMatch | null;
    findUnaryOverload(left: ITypeDeclaration): IOperatorMatch | false;
    findBinaryOverload(left: ITypeDeclaration, right: ITypeDeclaration): IOperatorMatch | false;
    checkBinaryOverload(left: ITypeDeclaration, right: ITypeDeclaration): ITypeDeclaration | false;
}
export interface IRegistry extends IRegistryBase {
    objectTypes: Map<string, IObjectTypeEntry>;
    objectTypesByConstructor: Map<object, IObjectTypeEntry>;
    operatorCandidates(op: string): ICandidates;
    functionCandidates(rec: boolean, name: string, argLen: number): ICandidates;
    findBinaryOverload(op: string, left: ITypeDeclaration, right: ITypeDeclaration): IOperatorMatch | false;
    findUnaryOverload(op: string, left: ITypeDeclaration): IOperatorMatch | false;
    getType(typename: string): ITypeDeclaration;
}
export interface IContextBase {
    getValue(key: string): unknown;
    getVariable(name: string): {
        type: ITypeDeclaration;
        constant: boolean;
        value: unknown;
        name: string;
    } | undefined;
    getCheckedValue(ev: IEvaluatorBase, ast: IASTNode): unknown;
    forkWithVariable(iterVar: string, iterType: ITypeDeclaration): IOverlayContextBase;
    accuType?: ITypeDeclaration;
    accuValue?: unknown;
}
export interface IOverlayContextBase extends IContextBase {
    iterValue: unknown;
    iterVar: string;
    iterType: ITypeDeclaration;
    reuse(parent: IContextBase): IOverlayContextBase;
    setIterValue(v: unknown, ev: IEvaluatorBase): this;
    setAccuType(type: ITypeDeclaration): this;
    setAccuValue(v: unknown): this;
}
/** ASTNode fields set dynamically during type-checking */
export interface IASTNodeDynamic {
    left?: IASTNode;
    right?: IASTNode;
    condition?: IASTNode;
    handle?: (...args: unknown[]) => unknown;
    candidates?: ICandidates;
    argTypes?: ITypeDeclaration[];
    leftStaticType?: ITypeDeclaration;
    rightStaticType?: ITypeDeclaration;
    receiverWithArgs?: IASTNode[];
    checkedType?: ITypeDeclaration;
}
export interface IASTNode extends IASTNodeDynamic {
    readonly op: string;
    args: unknown;
    readonly input: string;
    readonly pos: number;
    readonly start: number;
    readonly end: number;
    readonly meta: ASTMeta;
    readonly range: {
        start: number;
        end: number;
    };
    check(chk: ITypeCheckerBase, ast: IASTNode, ctx: IContextBase): ITypeDeclaration;
    evaluate(ev: IFullEvaluator, ast: IASTNode, ctx: IContextBase): Effect.Effect<unknown, unknown>;
    setMeta(key: string, value: unknown): IASTNode;
    clone(op: IOperatorDef, args: unknown): IASTNode;
    toOldStructure(): unknown[];
}
export interface ITypeCheckerBase {
    check(ast: IASTNode, ctx: IContextBase): ITypeDeclaration;
    checkAccessOnType(ast: IASTNode, ctx: IContextBase, leftType: ITypeDeclaration, allowMissingField?: boolean): ITypeDeclaration;
    registry: IRegistry;
    dynType: ITypeDeclaration;
    boolType: ITypeDeclaration;
    getType(typename: string): ITypeDeclaration;
    createError(code: string | {
        code?: string;
        message: string;
        node?: IASTNode;
        cause?: unknown;
    }, message?: string, node?: IASTNode): Error;
    formatType(type: ITypeDeclaration): string;
    formatTypeList(types: ITypeDeclaration[]): string;
    objectTypes: Map<string, IObjectTypeEntry>;
    debugType(v: unknown): ITypeDeclaration;
}
/** Full evaluator interface used in operator check/evaluate functions */
export interface IFullEvaluator extends IEvaluatorBase {
    dynType: ITypeDeclaration;
    optionalType: ITypeDeclaration;
    listType: ITypeDeclaration;
    registry: IRegistry;
    createError(code: string | {
        code?: string;
        message: string;
        node?: IASTNode;
        cause?: unknown;
    }, message?: string, node?: IASTNode): Error;
    eval(ast: IASTNode, ctx: IContextBase): Effect.Effect<unknown, unknown>;
    tryEval(ast: IASTNode, ctx: IContextBase): Effect.Effect<Either.Either<unknown, unknown>, never>;
    debugTypeDeep(value: unknown): ITypeDeclaration;
    debugRuntimeType(value: unknown, checkedType?: ITypeDeclaration): ITypeDeclaration;
}
export interface IOperatorDef {
    name: string;
    alias?: string;
    check: (chk: ITypeCheckerBase, ast: IASTNode, ctx: IContextBase) => ITypeDeclaration;
    evaluate: (ev: IFullEvaluator, ast: IASTNode, ctx: IContextBase) => Effect.Effect<unknown, unknown>;
}
export interface ASTMeta {
    check: IOperatorDef['check'];
    evaluate: IOperatorDef['evaluate'];
    alternate?: IASTNode;
    macro?: IMacroExpansion;
    label?: string;
    [key: string]: unknown;
}
export interface IMacroExpansion {
    callAst?: IASTNode;
    evaluate: (ev: IFullEvaluator, macro: IMacroExpansion, ctx: IContextBase) => Effect.Effect<unknown, unknown>;
    typeCheck: (chk: ITypeCheckerBase, macro: IMacroExpansion, ctx: IContextBase) => ITypeDeclaration;
    [key: string]: unknown;
}
/** Args shape for comprehension AST nodes */
export interface ComprehensionArgs {
    errorsAreFatal?: boolean;
    iterable: IASTNode;
    iterVarName: string;
    init: IASTNode;
    step: IASTNode;
    condition?: (accu: unknown) => unknown;
    result: (accu: unknown) => unknown;
    kind?: string;
    iterCtx?: IOverlayContextBase;
}
