/**
 * Cloud-agnostic LLM provider interfaces.
 *
 * Provides a unified chat completion API that works with
 * Azure OpenAI, OpenAI direct, Perplexity, Gemini, or mock providers.
 * Supports text, vision (image), and embedding modalities.
 */

// ── Content Parts (vision support) ────────────────────────────────

/** A text segment within a multipart message. */
export interface TextContentPart {
  type: 'text';
  text: string;
}

/** An image URL segment within a multipart message (vision). */
export interface ImageUrlContentPart {
  type: 'image_url';
  image_url: { url: string; detail?: 'auto' | 'low' | 'high' };
}

/** A single part of a multipart message — text or image. */
export type ContentPart = TextContentPart | ImageUrlContentPart;

// ── Chat Messages ─────────────────────────────────────────────────

export interface ChatMessage {
  role: 'system' | 'user' | 'assistant' | 'tool';
  /** Text string OR multipart content array (for vision messages). */
  content: string | ContentPart[];
  name?: string;
}

// ── Provider Interface ────────────────────────────────────────────

export interface LLMProvider {
  /** Send a chat completion request. */
  chatCompletion(req: ChatCompletionRequest): Promise<ChatCompletionResponse>;

  /** Stream a chat completion response — yields content delta strings. */
  chatCompletionStream?(req: ChatCompletionRequest): AsyncIterable<string>;

  /** Generate vector embeddings for input text(s). */
  embed?(req: EmbeddingRequest): Promise<EmbeddingResponse>;

  /** Check if the provider is configured with valid credentials. */
  isConfigured(): boolean;
}

// ── Chat Completion ───────────────────────────────────────────────

export interface ChatCompletionRequest {
  messages: ChatMessage[];
  model?: string;
  temperature?: number;
  maxTokens?: number;
  topP?: number;
  stop?: string[];
  responseFormat?: { type: 'text' | 'json_object' };
}

export interface ChatCompletionResponse {
  content: string;
  model: string;
  usage: TokenUsage;
  finishReason: 'stop' | 'length' | 'content_filter' | 'tool_calls' | null;
}

// ── Embeddings ────────────────────────────────────────────────────

export interface EmbeddingRequest {
  /** One or more texts to embed. */
  input: string | string[];
  /** Override the default embedding model. */
  model?: string;
}

export interface EmbeddingResponse {
  /** One embedding vector per input string. */
  embeddings: number[][];
  model: string;
  usage: TokenUsage;
}

// ── Shared ────────────────────────────────────────────────────────

export interface TokenUsage {
  promptTokens: number;
  completionTokens: number;
  totalTokens: number;
}

export type LLMProviderType = 'azure' | 'openai' | 'perplexity' | 'gemini' | 'fallback' | 'mock';

// ── Helpers ───────────────────────────────────────────────────────

/** Type guard: does this message contain image content parts? */
export function isVisionMessage(msg: ChatMessage): boolean {
  if (typeof msg.content === 'string') return false;
  return msg.content.some(p => p.type === 'image_url');
}

/** Does the request contain any vision (image) messages? */
export function hasVisionContent(req: ChatCompletionRequest): boolean {
  return req.messages.some(isVisionMessage);
}

/** Convenience builder for a user message with text + image. */
export function buildVisionMessage(
  text: string,
  imageUrl: string,
  detail: 'auto' | 'low' | 'high' = 'auto'
): ChatMessage {
  return {
    role: 'user',
    content: [
      { type: 'text', text },
      { type: 'image_url', image_url: { url: imageUrl, detail } },
    ],
  };
}

/** Extract plain text from a ChatMessage content (string or multipart). */
export function getMessageText(msg: ChatMessage): string {
  if (typeof msg.content === 'string') return msg.content;
  return msg.content
    .filter((p): p is TextContentPart => p.type === 'text')
    .map(p => p.text)
    .join('\n');
}
