// Package llm 提供与具体 provider 解耦的 LLM 抽象层。
// 所有 provider 实现都把 SDK 的 message/event 形态映射到本包定义的中立类型。
package llm

import "context"

// Role 标识消息发送方。
type Role string

const (
	RoleUser      Role = "user"
	RoleAssistant Role = "assistant"
)

// ContentBlock 是消息内容的最小单元。MVP 仅 text/image/document；tool_use/tool_result 为 mcp 预留。
type ContentBlock struct {
	Type     string // "text" | "image" | "document" | "tool_use" | "tool_result"
	Text     string // type=text
	MimeType string // type=image|document
	Data     []byte // type=image|document（原始字节，未编码；各 provider 实现内部 base64）
}

// Message 是一轮对话的中立表示。
type Message struct {
	Role   Role
	Blocks []ContentBlock
}

// ToolSpec 为 mcp 模块预留；MVP 始终空切片。
type ToolSpec struct {
	Name        string
	Description string
	InputSchema map[string]any
}

// Request 是 Stream/CountTokens 共用的输入。
type Request struct {
	SystemPrompt    string
	Messages        []Message
	MaxOutputTokens int
	Reasoning       bool
	Tools           []ToolSpec // mcp 预留
}

// StreamEventType 枚举所有流事件。
type StreamEventType string

const (
	EventTextDelta     StreamEventType = "text_delta"
	EventThinkingDelta StreamEventType = "thinking_delta"
	EventToolCall      StreamEventType = "tool_call" // 预留
	EventUsage         StreamEventType = "usage"
	EventDone          StreamEventType = "done"
	EventError         StreamEventType = "error"
)

// Usage 携带本次调用的 token 计数。
type Usage struct {
	PromptTokens     int
	CompletionTokens int
	ThinkingTokens   int
}

// StreamEvent 是流通道里的统一事件结构。
type StreamEvent struct {
	Type   StreamEventType
	Text   string // text_delta / thinking_delta
	Usage  *Usage // usage
	Err    error  // error
	Reason string // done.finish_reason
}

// LLMClient 是 Anthropic / OpenAI / Gemini 各自实现的统一接口。
type LLMClient interface {
	Provider() string
	// Stream 启动一次流式请求，返回事件 channel。channel 关闭即表示流结束。
	// ctx 取消时实现层须立即终止上游 stream。
	Stream(ctx context.Context, modelID string, req Request) (<-chan StreamEvent, error)
	// CountTokens 返回精确 token 数（远程接口）；仅 admin 离线场景使用。
	CountTokens(ctx context.Context, modelID string, req Request) (int, error)
}
