import { Cognitive, Models, Model, BotpressClientLike, GenerateContentInput, GenerateContentOutput } from '@botpress/cognitive';
import { TextTokenizer } from '@bpinternal/thicktoken';

type GenerationMetadata = {
    model: string;
    cost: {
        input: number;
        output: number;
    };
    latency: number;
    tokens: {
        input: number;
        output: number;
    };
};

type SaveExampleProps<TInput, TOutput> = {
    key: string;
    taskType: string;
    taskId: string;
    instructions: string;
    input: TInput;
    output: TOutput;
    explanation?: string;
    metadata: GenerationMetadata;
    status?: 'pending' | 'approved';
};
type GetExamplesProps<TInput> = {
    taskType: string;
    taskId: string;
    input: TInput;
};
declare abstract class Adapter {
    abstract getExamples<TInput, TOutput>(props: GetExamplesProps<TInput>): Promise<Array<{
        key: string;
        input: TInput;
        output: TOutput;
        explanation?: string;
        similarity: number;
    }>>;
    abstract saveExample<TInput, TOutput>(props: SaveExampleProps<TInput, TOutput>): Promise<void>;
}

type ActiveLearning = {
    enable: boolean;
    tableName: string;
    taskId: string;
};
type ZaiConfig = {
    client: BotpressClientLike | Cognitive;
    userId?: string;
    modelId?: Models;
    activeLearning?: ActiveLearning;
    namespace?: string;
};
declare class Zai {
    protected static tokenizer: TextTokenizer;
    protected client: Cognitive;
    private _originalConfig;
    private _userId;
    protected Model: Models;
    protected ModelDetails: Model;
    protected namespace: string;
    protected adapter: Adapter;
    protected activeLearning: ActiveLearning;
    constructor(config: ZaiConfig);
    /** @internal */
    protected callModel(props: Parameters<Cognitive['generateContent']>[0]): ReturnType<Cognitive['generateContent']>;
    protected getTokenizer(): Promise<TextTokenizer>;
    protected fetchModelDetails(): Promise<void>;
    protected get taskId(): string;
    with(options: Partial<ZaiConfig>): Zai;
    learn(taskId: string): Zai;
}

type Meta = Awaited<ReturnType<Cognitive['generateContent']>>['meta'];
type GenerateContentProps<T> = Omit<GenerateContentInput, 'model' | 'signal'> & {
    maxRetries?: number;
    transform?: (text: string | undefined, output: GenerateContentOutput) => T;
};
type ZaiContextProps = {
    client: Cognitive;
    taskType: string;
    taskId: string;
    modelId: string;
    adapter?: Adapter;
    source?: GenerateContentInput['meta'];
};
type Usage = {
    requests: {
        requests: number;
        errors: number;
        responses: number;
        cached: number;
        percentage: number;
    };
    cost: {
        input: number;
        output: number;
        total: number;
    };
    tokens: {
        input: number;
        output: number;
        total: number;
    };
};
type ContextEvents = {
    update: Usage;
};
declare class ZaiContext {
    private _startedAt;
    private _inputCost;
    private _outputCost;
    private _inputTokens;
    private _outputTokens;
    private _totalCachedResponses;
    private _totalRequests;
    private _totalErrors;
    private _totalResponses;
    taskId: string;
    taskType: string;
    modelId: GenerateContentInput['model'];
    adapter?: Adapter;
    source?: GenerateContentInput['meta'];
    private _eventEmitter;
    controller: AbortController;
    private _client;
    constructor(props: ZaiContextProps);
    getModel(): Promise<Model>;
    on<K extends keyof ContextEvents>(type: K, listener: (event: ContextEvents[K]) => void): this;
    clear(): void;
    generateContent<Out = string>(props: GenerateContentProps<Out>): Promise<{
        meta: Meta;
        output: GenerateContentOutput;
        text: string | undefined;
        extracted: Out;
    }>;
    get elapsedTime(): number;
    get usage(): Usage;
}

type ResponseEvents<TComplete = any> = {
    progress: Usage;
    complete: TComplete;
    error: unknown;
};
declare class Response<T = any, S = T> implements PromiseLike<S> {
    private _promise;
    private _eventEmitter;
    private _context;
    private _elasped;
    private _simplify;
    constructor(context: ZaiContext, promise: Promise<T>, simplify: (value: T) => S);
    on<K extends keyof ResponseEvents<T>>(type: K, listener: (event: ResponseEvents<T>[K]) => void): this;
    off<K extends keyof ResponseEvents<T>>(type: K, listener: (event: ResponseEvents<T>[K]) => void): this;
    once<K extends keyof ResponseEvents<T>>(type: K, listener: (event: ResponseEvents<T>[K]) => void): this;
    bindSignal(signal: AbortSignal): this;
    abort(reason?: string | Error): void;
    then<TResult1 = S, TResult2 = never>(onfulfilled?: ((value: S) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
    catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null): PromiseLike<S | TResult>;
    result(): Promise<{
        output: T;
        usage: Usage;
        elapsed: number;
    }>;
}

type Options$a = {
    /** The maximum number of tokens to generate */
    length?: number;
};
declare module '@botpress/zai' {
    interface Zai {
        /** Generates a text of the desired length according to the prompt */
        text(prompt: string, options?: Options$a): Response<string>;
    }
}

type Example$3 = {
    input: string;
    output: string;
    instructions?: string;
};
type Options$9 = {
    /** Examples to guide the rewriting */
    examples?: Array<Example$3>;
    /** The maximum number of tokens to generate */
    length?: number;
};
declare module '@botpress/zai' {
    interface Zai {
        /** Rewrites a string according to match the prompt */
        rewrite(original: string, prompt: string, options?: Options$9): Response<string>;
    }
}

type Options$8 = {
    /** What should the text be summarized to? */
    prompt?: string;
    /** How to format the example text */
    format?: string;
    /** The length of the summary in tokens */
    length?: number;
    /** How many times longer (than final length) are the intermediate summaries generated */
    intermediateFactor?: number;
    /** The maximum number of iterations to perform */
    maxIterations?: number;
    /** Sliding window options */
    sliding?: {
        window: number;
        overlap: number;
    };
};
declare module '@botpress/zai' {
    interface Zai {
        /** Summarizes a text of any length to a summary of the desired length */
        summarize(original: string, options?: Options$8): Response<string>;
    }
}

type Example$2 = {
    input: unknown;
    check: boolean;
    reason?: string;
    condition?: string;
};
type Options$7 = {
    /** Examples to check the condition against */
    examples?: Array<Example$2>;
};
declare module '@botpress/zai' {
    interface Zai {
        /** Checks wether a condition is true or not */
        check(input: unknown, condition: string, options?: Options$7): Response<{
            /** Whether the condition is true or not */
            value: boolean;
            /** The explanation of the decision */
            explanation: string;
        }, boolean>;
    }
}

type Example$1 = {
    input: unknown;
    filter: boolean;
    reason?: string;
};
type Options$6 = {
    /** The maximum number of tokens per item */
    tokensPerItem?: number;
    /** Examples to filter the condition against */
    examples?: Array<Example$1>;
};
declare module '@botpress/zai' {
    interface Zai {
        /** Filters elements of an array against a condition */
        filter<T>(input: Array<T>, condition: string, options?: Options$6): Response<Array<T>>;
    }
}

type Options$5 = {
    /** Instructions to guide the user on how to extract the data */
    instructions?: string;
    /** The maximum number of tokens per chunk */
    chunkLength?: number;
    /** Whether to strictly follow the schema or not */
    strict?: boolean;
};
type __Z<T extends any = any> = {
    _output: T;
};
type OfType<O, T extends __Z = __Z<O>> = T extends __Z<O> ? T : never;
declare module '@botpress/zai' {
    interface Zai {
        /** Extracts one or many elements from an arbitrary input */
        extract<S extends OfType<any>>(input: unknown, schema: S, options?: Options$5): Response<S['_output']>;
    }
}

type Label = keyof typeof LABELS;
declare const LABELS: {
    readonly ABSOLUTELY_NOT: "ABSOLUTELY_NOT";
    readonly PROBABLY_NOT: "PROBABLY_NOT";
    readonly AMBIGUOUS: "AMBIGUOUS";
    readonly PROBABLY_YES: "PROBABLY_YES";
    readonly ABSOLUTELY_YES: "ABSOLUTELY_YES";
};
type Example<T extends string> = {
    input: unknown;
    labels: Partial<Record<T, {
        label: Label;
        explanation?: string;
    }>>;
};
type Options$4<T extends string> = {
    /** Examples to help the user make a decision */
    examples?: Array<Example<T>>;
    /** Instructions to guide the user on how to extract the data */
    instructions?: string;
    /** The maximum number of tokens per chunk */
    chunkLength?: number;
};
type Labels<T extends string> = Record<T, string>;
declare module '@botpress/zai' {
    interface Zai {
        /** Tags the provided input with a list of predefined labels */
        label<T extends string>(input: unknown, labels: Labels<T>, options?: Options$4<T>): Response<{
            [K in T]: {
                explanation: string;
                value: boolean;
                confidence: number;
            };
        }, {
            [K in T]: boolean;
        }>;
    }
}

type Group<T> = {
    id: string;
    label: string;
    elements: T[];
};
type InitialGroup = {
    id: string;
    label: string;
    elements?: unknown[];
};
type Options$3 = {
    instructions?: string;
    tokensPerElement?: number;
    chunkLength?: number;
    initialGroups?: Array<InitialGroup>;
};
declare module '@botpress/zai' {
    interface Zai {
        group<T>(input: Array<T>, options?: Options$3): Response<Array<Group<T>>, Record<string, T[]>>;
    }
}

type RatingInstructions = string | Record<string, string>;
type Options$2 = {
    /** The maximum number of tokens per item */
    tokensPerItem?: number;
    /** The maximum number of items to rate per chunk */
    maxItemsPerChunk?: number;
};
type RatingResult<T extends RatingInstructions> = T extends string ? {
    [key: string]: number;
    total: number;
} : T extends Record<string, string> ? {
    [K in keyof T]: number;
} & {
    total: number;
} : never;
type SimplifiedRatingResult<T extends RatingInstructions> = T extends string ? number : RatingResult<T>;
declare module '@botpress/zai' {
    interface Zai {
        /**
         * Rates an array of items based on provided instructions.
         * Returns a number (1-5) if instructions is a string, or a Record<string, number> if instructions is a Record.
         */
        rate<T, I extends RatingInstructions>(input: Array<T>, instructions: I, options?: Options$2): Response<Array<RatingResult<I>>, Array<SimplifiedRatingResult<I>>>;
    }
}

type Options$1 = {
    /** The maximum number of tokens per item */
    tokensPerItem?: number;
};
declare module '@botpress/zai' {
    interface Zai {
        /**
         * Sorts an array of items based on provided instructions.
         * Returns the sorted array directly when awaited.
         * Use .result() to get detailed scoring information including why each item got its position.
         *
         * @example
         * // Simple usage
         * const sorted = await zai.sort(items, 'from least expensive to most expensive')
         *
         * @example
         * // Get detailed results
         * const { output: sorted, usage } = await zai.sort(items, 'by priority').result()
         */
        sort<T>(input: Array<T>, instructions: string, options?: Options$1): Response<Array<T>, Array<T>>;
    }
}

/**
 * Citation referencing a specific line or range of lines in support documents
 */
type Citation<T> = {
    /** The character offset where this citation appears in the answer */
    offset: number;
    /** The support document item(s) used at this offset */
    item: T;
    /** The line contents joined together as a snippet */
    snippet: string;
};
/**
 * A single answer with citations
 */
type AnswerWithCitations<T> = {
    /** The answer text */
    answer: string;
    /** Citations mapping answer text to support documents */
    citations: Citation<T>[];
};
/**
 * Response type when a clear answer can be provided
 */
type AnswerResponse<T> = {
    type: 'answer';
} & AnswerWithCitations<T>;
/**
 * Response type when the question is ambiguous and multiple interpretations exist
 */
type AmbiguousResponse<T> = {
    type: 'ambiguous';
    /** What is the ambiguity? What concepts clash or are unclear? */
    ambiguity: string;
    /** A follow-up question to clear out the ambiguity */
    follow_up: string;
    /** Possible answers for different interpretations (2-3 answers) */
    answers: AnswerWithCitations<T>[];
};
/**
 * Response type when the question is out of topic
 */
type OutOfTopicResponse = {
    type: 'out_of_topic';
    /** Why is this question considered out of topic? */
    reason: string;
};
/**
 * Response type when the question is invalid or malformed
 */
type InvalidQuestionResponse = {
    type: 'invalid_question';
    /** What makes this an invalid question? */
    reason: string;
};
/**
 * Response type when there is insufficient knowledge to answer
 */
type MissingKnowledgeResponse = {
    type: 'missing_knowledge';
    /** What knowledge is missing to generate a high-quality answer? */
    reason: string;
};
/**
 * All possible response types from zai.answer
 */
type AnswerResult<T> = AnswerResponse<T> | AmbiguousResponse<T> | OutOfTopicResponse | InvalidQuestionResponse | MissingKnowledgeResponse;
/**
 * Example for few-shot learning
 */
type AnswerExample<T> = {
    /** Support documents for this example */
    documents: T[];
    /** The question asked */
    question: string;
    /** The expected answer result */
    result: AnswerResult<T>;
};
type Options<T> = {
    /** Examples to help guide answer generation */
    examples?: AnswerExample<T>[];
    /** Additional instructions for answer generation */
    instructions?: string;
    /** Maximum number of tokens per document chunk */
    chunkLength?: number;
    /**
     * Maximum number of refinement iterations when merging chunked results
     * @default 3
     */
    maxRefinementPasses?: number;
};
declare module '@botpress/zai' {
    interface Zai {
        /**
         * Answer questions from a list of support documents with citations
         * @param documents - Array of support documents (can be strings, objects, etc.)
         * @param question - The question to answer
         * @param options - Optional configuration
         * @returns Response with answer and citations, or other response types (ambiguous, out_of_topic, etc.)
         */
        answer<T>(documents: T[], question: string, options?: Options<T>): Response<AnswerResult<T>, AnswerResult<T>>;
    }
}

export { Zai };
