package anthropic

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"nex/backend/internal/conversion"
	"nex/backend/internal/conversion/canonical"
)

// decodeRequest 将 Anthropic 请求解码为 Canonical 请求
func decodeRequest(body []byte) (*canonical.CanonicalRequest, error) {
	var req MessagesRequest
	if err := json.Unmarshal(body, &req); err != nil {
		return nil, conversion.NewConversionError(conversion.ErrorCodeJSONParseError, "解析 Anthropic 请求失败").WithCause(err)
	}

	if strings.TrimSpace(req.Model) == "" {
		return nil, conversion.NewConversionError(conversion.ErrorCodeInvalidInput, "model 字段不能为空")
	}
	if len(req.Messages) == 0 {
		return nil, conversion.NewConversionError(conversion.ErrorCodeInvalidInput, "messages 字段不能为空")
	}

	system := decodeSystem(req.System)

	var canonicalMsgs []canonical.CanonicalMessage
	for _, msg := range req.Messages {
		decoded, err := decodeMessage(msg)
		if err != nil {
			return nil, conversion.NewConversionError(conversion.ErrorCodeJSONParseError, "解析消息内容失败").WithCause(err)
		}
		canonicalMsgs = append(canonicalMsgs, decoded...)
	}

	tools := decodeTools(req.Tools)
	toolChoice := decodeToolChoice(req.ToolChoice)
	params := decodeParameters(&req)
	thinking := decodeThinking(req.Thinking, req.OutputConfig)
	outputFormat := decodeOutputFormat(req.OutputConfig)

	var parallelToolUse *bool
	if req.DisableParallelToolUse != nil && *req.DisableParallelToolUse {
		val := false
		parallelToolUse = &val
	}

	var userID string
	if req.Metadata != nil {
		userID = req.Metadata.UserID
	}

	return &canonical.CanonicalRequest{
		Model:           req.Model,
		System:          system,
		Messages:        canonicalMsgs,
		Tools:           tools,
		ToolChoice:      toolChoice,
		Parameters:      params,
		Thinking:        thinking,
		Stream:          req.Stream,
		UserID:          userID,
		OutputFormat:    outputFormat,
		ParallelToolUse: parallelToolUse,
	}, nil
}

// decodeSystem 解码系统消息
func decodeSystem(system any) any {
	if system == nil {
		return nil
	}
	switch v := system.(type) {
	case string:
		if v == "" {
			return nil
		}
		return v
	case []any:
		var blocks []canonical.SystemBlock
		for _, item := range v {
			if m, ok := item.(map[string]any); ok {
				if text, ok := m["text"].(string); ok {
					blocks = append(blocks, canonical.SystemBlock{Text: text})
				}
			}
		}
		if len(blocks) == 0 {
			return nil
		}
		return blocks
	default:
		return fmt.Sprintf("%v", v)
	}
}

// decodeMessage 解码 Anthropic 消息
func decodeMessage(msg Message) ([]canonical.CanonicalMessage, error) {
	switch msg.Role {
	case "user":
		blocks, err := decodeContentBlocks(msg.Content)
		if err != nil {
			return nil, err
		}
		var toolResults []canonical.ContentBlock
		var others []canonical.ContentBlock
		for _, b := range blocks {
			if b.Type == "tool_result" {
				toolResults = append(toolResults, b)
			} else {
				others = append(others, b)
			}
		}
		var result []canonical.CanonicalMessage
		if len(others) > 0 {
			result = append(result, canonical.CanonicalMessage{Role: canonical.RoleUser, Content: others})
		}
		if len(toolResults) > 0 {
			result = append(result, canonical.CanonicalMessage{Role: canonical.RoleTool, Content: toolResults})
		}
		if len(result) == 0 {
			result = append(result, canonical.CanonicalMessage{Role: canonical.RoleUser, Content: []canonical.ContentBlock{canonical.NewTextBlock("")}})
		}
		return result, nil

	case "assistant":
		blocks, err := decodeContentBlocks(msg.Content)
		if err != nil {
			return nil, err
		}
		if len(blocks) == 0 {
			blocks = append(blocks, canonical.NewTextBlock(""))
		}
		return []canonical.CanonicalMessage{{Role: canonical.RoleAssistant, Content: blocks}}, nil
	}
	return nil, nil
}

// decodeContentBlocks 解码内容块列表
func decodeContentBlocks(content any) ([]canonical.ContentBlock, error) {
	switch v := content.(type) {
	case string:
		return []canonical.ContentBlock{canonical.NewTextBlock(v)}, nil
	case []any:
		var blocks []canonical.ContentBlock
		for _, item := range v {
			if m, ok := item.(map[string]any); ok {
				block, err := decodeSingleContentBlock(m)
				if err != nil {
					return nil, err
				}
				if block != nil {
					blocks = append(blocks, *block)
				}
			}
		}
		if len(blocks) > 0 {
			return blocks, nil
		}
		return []canonical.ContentBlock{canonical.NewTextBlock("")}, nil
	case nil:
		return []canonical.ContentBlock{canonical.NewTextBlock("")}, nil
	default:
		return []canonical.ContentBlock{canonical.NewTextBlock(fmt.Sprintf("%v", v))}, nil
	}
}

// decodeSingleContentBlock 解码单个内容块
func decodeSingleContentBlock(m map[string]any) (*canonical.ContentBlock, error) {
	t, ok := m["type"].(string)
	if !ok {
		return nil, nil
	}

	switch t {
	case "text":
		text, ok := m["text"].(string)
		if !ok {
			text = ""
		}
		return &canonical.ContentBlock{Type: "text", Text: text}, nil
	case "tool_use":
		id, ok := m["id"].(string)
		if !ok {
			id = ""
		}
		name, ok := m["name"].(string)
		if !ok {
			name = ""
		}
		input, err := json.Marshal(m["input"])
		if err != nil {
			return nil, err
		}
		return &canonical.ContentBlock{Type: "tool_use", ID: id, Name: name, Input: input}, nil
	case "tool_result":
		toolUseID, ok := m["tool_use_id"].(string)
		if !ok {
			toolUseID = ""
		}
		isErr := false
		if ie, ok := m["is_error"].(bool); ok {
			isErr = ie
		}
		var content json.RawMessage
		if c, ok := m["content"]; ok {
			switch cv := c.(type) {
			case string:
				content = json.RawMessage(fmt.Sprintf("%q", cv))
			default:
				encoded, err := json.Marshal(cv)
				if err != nil {
					return nil, err
				}
				content = encoded
			}
		} else {
			content = json.RawMessage(`""`)
		}
		return &canonical.ContentBlock{
			Type:      "tool_result",
			ToolUseID: toolUseID,
			Content:   content,
			IsError:   &isErr,
		}, nil
	case "thinking":
		thinking, ok := m["thinking"].(string)
		if !ok {
			thinking = ""
		}
		return &canonical.ContentBlock{Type: "thinking", Thinking: thinking}, nil
	case "redacted_thinking":
		// 丢弃
		return nil, nil
	}
	return nil, nil
}

// decodeTools 解码工具定义
func decodeTools(tools []Tool) []canonical.CanonicalTool {
	if len(tools) == 0 {
		return nil
	}
	result := make([]canonical.CanonicalTool, len(tools))
	for i, t := range tools {
		result[i] = canonical.CanonicalTool{
			Name:        t.Name,
			Description: t.Description,
			InputSchema: t.InputSchema,
		}
	}
	return result
}

// decodeToolChoice 解码工具选择
func decodeToolChoice(toolChoice any) *canonical.ToolChoice {
	if toolChoice == nil {
		return nil
	}
	switch v := toolChoice.(type) {
	case string:
		switch v {
		case "auto":
			return canonical.NewToolChoiceAuto()
		case "none":
			return canonical.NewToolChoiceNone()
		case "any":
			return canonical.NewToolChoiceAny()
		}
	case map[string]any:
		t, ok := v["type"].(string)
		if !ok {
			return nil
		}
		switch t {
		case "auto":
			return canonical.NewToolChoiceAuto()
		case "none":
			return canonical.NewToolChoiceNone()
		case "any":
			return canonical.NewToolChoiceAny()
		case "tool":
			name, ok := v["name"].(string)
			if !ok {
				name = ""
			}
			return canonical.NewToolChoiceNamed(name)
		}
	}
	return nil
}

// decodeParameters 解码请求参数
func decodeParameters(req *MessagesRequest) canonical.RequestParameters {
	params := canonical.RequestParameters{
		Temperature: req.Temperature,
		TopP:        req.TopP,
		TopK:        req.TopK,
	}
	if req.MaxTokens > 0 {
		val := req.MaxTokens
		params.MaxTokens = &val
	}
	if len(req.StopSequences) > 0 {
		params.StopSequences = req.StopSequences
	}
	return params
}

// decodeThinking 解码思考配置
func decodeThinking(thinking *ThinkingConfig, outputConfig *OutputConfig) *canonical.ThinkingConfig {
	if thinking == nil {
		return nil
	}
	cfg := &canonical.ThinkingConfig{
		Type:         thinking.Type,
		BudgetTokens: thinking.BudgetTokens,
	}
	if outputConfig != nil && outputConfig.Effort != "" {
		cfg.Effort = outputConfig.Effort
	}
	return cfg
}

// decodeOutputFormat 解码输出格式
func decodeOutputFormat(outputConfig *OutputConfig) *canonical.OutputFormat {
	if outputConfig == nil || outputConfig.Format == nil {
		return nil
	}
	if outputConfig.Format.Type == "json_schema" && outputConfig.Format.Schema != nil {
		return &canonical.OutputFormat{
			Type:   "json_schema",
			Name:   "output",
			Schema: outputConfig.Format.Schema,
			Strict: boolPtr(true),
		}
	}
	return nil
}

// decodeResponse 将 Anthropic 响应解码为 Canonical 响应
func decodeResponse(body []byte) (*canonical.CanonicalResponse, error) {
	var resp MessagesResponse
	if err := json.Unmarshal(body, &resp); err != nil {
		return nil, conversion.NewConversionError(conversion.ErrorCodeJSONParseError, "解析 Anthropic 响应失败").WithCause(err)
	}

	var blocks []canonical.ContentBlock
	for _, block := range resp.Content {
		switch block.Type {
		case "text":
			blocks = append(blocks, canonical.NewTextBlock(block.Text))
		case "tool_use":
			blocks = append(blocks, canonical.NewToolUseBlock(block.ID, block.Name, block.Input))
		case "thinking":
			blocks = append(blocks, canonical.NewThinkingBlock(block.Thinking))
		case "redacted_thinking":
			// 丢弃
		}
	}
	if len(blocks) == 0 {
		blocks = append(blocks, canonical.NewTextBlock(""))
	}

	sr := mapStopReason(resp.StopReason)
	usage := canonical.CanonicalUsage{
		InputTokens:  resp.Usage.InputTokens,
		OutputTokens: resp.Usage.OutputTokens,
	}
	if resp.Usage.CacheReadInputTokens != nil {
		usage.CacheReadTokens = resp.Usage.CacheReadInputTokens
	}
	if resp.Usage.CacheCreationInputTokens != nil {
		usage.CacheCreationTokens = resp.Usage.CacheCreationInputTokens
	}

	return &canonical.CanonicalResponse{
		ID:         resp.ID,
		Model:      resp.Model,
		Content:    blocks,
		StopReason: &sr,
		Usage:      usage,
	}, nil
}

// mapStopReason 映射停止原因
func mapStopReason(reason string) canonical.StopReason {
	switch reason {
	case "end_turn":
		return canonical.StopReasonEndTurn
	case "max_tokens":
		return canonical.StopReasonMaxTokens
	case "tool_use":
		return canonical.StopReasonToolUse
	case "stop_sequence":
		return canonical.StopReasonStopSequence
	case "pause_turn":
		return canonical.StopReason("pause_turn")
	case "refusal":
		return canonical.StopReasonRefusal
	default:
		return canonical.StopReasonEndTurn
	}
}

// decodeModelsResponse 解码模型列表响应
func decodeModelsResponse(body []byte) (*canonical.CanonicalModelList, error) {
	var resp ModelsResponse
	if err := json.Unmarshal(body, &resp); err != nil {
		return nil, err
	}
	models := make([]canonical.CanonicalModel, len(resp.Data))
	for i, m := range resp.Data {
		name := m.DisplayName
		if name == "" {
			name = m.ID
		}
		models[i] = canonical.CanonicalModel{
			ID:      m.ID,
			Name:    name,
			Created: parseTimestamp(m.CreatedAt),
			OwnedBy: "anthropic",
		}
	}
	return &canonical.CanonicalModelList{Models: models}, nil
}

// decodeModelInfoResponse 解码模型详情响应
func decodeModelInfoResponse(body []byte) (*canonical.CanonicalModelInfo, error) {
	var resp ModelInfoResponse
	if err := json.Unmarshal(body, &resp); err != nil {
		return nil, err
	}
	name := resp.DisplayName
	if name == "" {
		name = resp.ID
	}
	return &canonical.CanonicalModelInfo{
		ID:      resp.ID,
		Name:    name,
		Created: parseTimestamp(resp.CreatedAt),
		OwnedBy: "anthropic",
	}, nil
}

// parseTimestamp 解析 RFC 3339 时间戳为 Unix
func parseTimestamp(s string) int64 {
	if s == "" {
		return 0
	}
	t, err := time.Parse(time.RFC3339, s)
	if err != nil {
		return 0
	}
	return t.Unix()
}

// formatTimestamp 将 Unix 时间戳格式化为 RFC 3339
func formatTimestamp(unix int64) string {
	if unix == 0 {
		return time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC).Format(time.RFC3339)
	}
	return time.Unix(unix, 0).UTC().Format(time.RFC3339)
}

// boolPtr 返回 bool 指针
func boolPtr(b bool) *bool {
	return &b
}
