import type { UnifiedDisposable } from '@gitlens/utils/disposable.js';
import type { Event } from '@gitlens/utils/event.js';
import type { AIProviders } from '../constants.js';
import type { AIActionType, AIModel } from './model.js';

export type AIChatMessageRole = 'assistant' | 'system' | 'user';

export type AISystemChatMessage = AIChatMessage<'system'>;
export interface AIChatMessage<T extends AIChatMessageRole = 'assistant' | 'user'> {
	role: T;
	content: string;
}

export interface AIProviderResponse<T> {
	readonly id: string;
	readonly content: string;
	readonly model: AIModel;

	readonly usage?: {
		readonly promptTokens?: number;
		readonly completionTokens?: number;
		readonly totalTokens?: number;

		readonly limits?: { readonly used: number; readonly limit: number; readonly resetsOn: Date };
	};

	readonly result: T;
}

export type AIProviderResult<T> = {
	readonly model: AIModel;

	readonly promise: Promise<AIProviderResponse<T> | 'cancelled' | undefined>;
};

export interface AIProvider<Provider extends AIProviders = AIProviders> extends UnifiedDisposable {
	readonly id: Provider;
	readonly name: string;

	onDidChange?: Event<void>;

	configured(silent: boolean): Promise<boolean>;
	getApiKey(silent: boolean): Promise<string | undefined>;
	getModels(): Promise<readonly AIModel<Provider>[]>;
	sendRequest<T extends AIActionType>(
		action: T,
		model: AIModel<Provider>,
		apiKey: string,
		getMessages: (maxInputTokens: number, retries: number) => Promise<AIChatMessage[]>,
		options: { signal: AbortSignal; modelOptions?: { outputTokens?: number; temperature?: number } },
	): Promise<AIProviderResponse<void> | undefined>;
}
