package agents

import "encoding/json"

// KB mode constants for AgentConfig.KBMode.
const (
	KBModeAutoSearch = "auto_search" // default: auto-search KB on each user message
	KBModeTools      = "tools"       // expose search_memory / add_memory as agent tools
	KBModeBoth       = "both"        // auto-search + tools
)

// Skills mode constants for AgentConfig.SkillsMode.
const (
	SkillsModePrompt = "prompt" // default: inject skill descriptions into system prompt
	SkillsModeTools  = "tools"  // expose skills as callable tools
	SkillsModeBoth   = "both"   // both prompt + tools
)

// Conversation storage mode constants for AgentConfig.ConversationStorageMode.
const (
	ConvStorageUserOnly          = "user_only"          // default: store only user messages
	ConvStorageUserAndAssistant  = "user_and_assistant" // store user and assistant messages separately
	ConvStorageWholeConversation = "whole_conversation" // store entire conversation as single block
)

// AgentConfig defines the configuration for an agent.
// JSON field names match LocalAGI's state.AgentConfig for import/export compatibility.
type AgentConfig struct {
	// Integrations
	Connector        []ConnectorConfig      `json:"connectors"`
	Actions          []ActionsConfig        `json:"actions"`
	DynamicPrompts   []DynamicPromptsConfig `json:"dynamic_prompts"`
	MCPServers       []MCPServer            `json:"mcp_servers"`
	MCPSTDIOServers  MCPSTDIOServers        `json:"mcp_stdio_servers"`
	MCPPrepareScript string                 `json:"mcp_prepare_script"`
	Filters          []FiltersConfig        `json:"filters"`

	// Basic info
	Description string `json:"description"`
	Name        string `json:"name"`

	// Models
	Model                 string `json:"model"`
	MultimodalModel       string `json:"multimodal_model"`
	TranscriptionModel    string `json:"transcription_model"`
	TranscriptionLanguage string `json:"transcription_language"`
	TTSModel              string `json:"tts_model"`

	// API
	APIURL         string `json:"api_url"`
	APIKey         string `json:"api_key"`
	LocalRAGURL    string `json:"local_rag_url"`
	LocalRAGAPIKey string `json:"local_rag_api_key"`

	// Timing
	LastMessageDuration   string `json:"last_message_duration"`
	PeriodicRuns          string `json:"periodic_runs"`
	SchedulerPollInterval string `json:"scheduler_poll_interval"`

	// Behavior
	StandaloneJob          bool   `json:"standalone_job"`
	InitiateConversations  bool   `json:"initiate_conversations"`
	CanPlan                bool   `json:"enable_planning"`
	PlanReviewerModel      string `json:"plan_reviewer_model"`
	DisableSinkState       bool   `json:"disable_sink_state"` // legacy, kept for JSON compat — sink state is always disabled
	PermanentGoal          string `json:"permanent_goal"`
	SystemPrompt           string `json:"system_prompt"`
	SkillsPrompt           string `json:"skills_prompt"`
	InnerMonologueTemplate string `json:"inner_monologue_template"`
	SchedulerTaskTemplate  string `json:"scheduler_task_template"`

	// Knowledge base
	EnableKnowledgeBase   bool   `json:"enable_kb"`
	KBMode                string `json:"kb_mode,omitempty"` // "auto_search" (default), "tools", "both"
	KnowledgeBaseResults  int    `json:"kb_results"`
	EnableKBCompaction    bool   `json:"enable_kb_compaction"`
	KBCompactionInterval  string `json:"kb_compaction_interval"`
	KBCompactionSummarize bool   `json:"kb_compaction_summarize"`
	KBAutoSearch          bool   `json:"kb_auto_search"` // legacy, kept for JSON compat
	KBAsTools             bool   `json:"kb_as_tools"`    // legacy, kept for JSON compat

	// Reasoning & tools
	EnableReasoning            bool `json:"enable_reasoning"`              // legacy, kept for JSON compat
	EnableForceReasoningTool   bool `json:"enable_reasoning_tool"`         // legacy, kept for JSON compat
	EnableReasoningForInstruct bool `json:"enable_reasoning_for_instruct"` // enables ForceReasoning + ForceReasoningTool
	EnableGuidedTools          bool `json:"enable_guided_tools"`
	CanStopItself              bool `json:"can_stop_itself"`

	// Skills
	EnableSkills   bool     `json:"enable_skills"`
	SkillsMode     string   `json:"skills_mode,omitempty"`     // "prompt" (default), "tools", or "both"
	SelectedSkills []string `json:"selected_skills,omitempty"` // Per-agent skill selection

	// Memory
	LongTermMemory          bool   `json:"long_term_memory"`
	SummaryLongTermMemory   bool   `json:"summary_long_term_memory"`
	ConversationStorageMode string `json:"conversation_storage_mode"`

	// Execution
	ParallelJobs               int   `json:"parallel_jobs"`
	CancelPreviousOnNewMessage *bool `json:"cancel_previous_on_new_message"`
	StripThinkingTags          bool  `json:"strip_thinking_tags"`
	EnableEvaluation           bool  `json:"enable_evaluation"`
	MaxEvaluationLoops         int   `json:"max_evaluation_loops"`
	MaxAttempts                int   `json:"max_attempts"`
	MaxIterations              int   `json:"max_iterations"` // max tool loop iterations
	LoopDetection              int   `json:"loop_detection"`
	EnableAutoCompaction       bool  `json:"enable_auto_compaction"`
	AutoCompactionThreshold    int   `json:"auto_compaction_threshold"`
}

// ConnectorConfig defines a connector integration (Slack, Discord, etc.).
type ConnectorConfig struct {
	Type   string `json:"type"`
	Config string `json:"config"`
}

// ActionsConfig defines an action (tool) available to the agent.
type ActionsConfig struct {
	Type   string `json:"type"`
	Config string `json:"config"`
}

// DynamicPromptsConfig defines a dynamic prompt template.
type DynamicPromptsConfig struct {
	Type   string `json:"type"`
	Config string `json:"config"`
}

// FiltersConfig defines a job filter/trigger.
type FiltersConfig struct {
	Type   string `json:"type"`
	Config string `json:"config"`
}

// MCPServer defines an HTTP-based MCP server endpoint.
type MCPServer struct {
	URL   string `json:"url"`
	Token string `json:"token"`
}

// MCPSTDIOServers is a list of stdio MCP servers that can be unmarshaled from
// either a JSON array of MCPSTDIOServer objects or a JSON string in Claude Desktop
// format ({"mcpServers": {"name": {"command": "...", "args": [...]}}}).
type MCPSTDIOServers []MCPSTDIOServer

// UnmarshalJSON handles both array and string (Claude Desktop JSON) formats.
func (m *MCPSTDIOServers) UnmarshalJSON(data []byte) error {
	// Try array format first
	var arr []MCPSTDIOServer
	if err := json.Unmarshal(data, &arr); err == nil {
		*m = arr
		return nil
	}

	// Try string format (Claude Desktop JSON blob)
	var raw string
	if err := json.Unmarshal(data, &raw); err == nil {
		parsed, err := parseClaudeDesktopMCP(raw)
		if err != nil {
			return nil // silently ignore unparseable strings
		}
		*m = parsed
		return nil
	}

	return nil
}

// parseClaudeDesktopMCP parses the {"mcpServers": {...}} format into MCPSTDIOServer list.
func parseClaudeDesktopMCP(raw string) ([]MCPSTDIOServer, error) {
	var wrapper struct {
		MCPServers map[string]struct {
			Command string            `json:"command"`
			Cmd     string            `json:"cmd"`
			Args    []string          `json:"args"`
			Env     map[string]string `json:"env"`
		} `json:"mcpServers"`
	}
	if err := json.Unmarshal([]byte(raw), &wrapper); err != nil {
		return nil, err
	}
	var result []MCPSTDIOServer
	for name, srv := range wrapper.MCPServers {
		cmd := srv.Command
		if cmd == "" {
			cmd = srv.Cmd
		}
		var envList []string
		for k, v := range srv.Env {
			envList = append(envList, k+"="+v)
		}
		result = append(result, MCPSTDIOServer{
			Name: name,
			Cmd:  cmd,
			Args: srv.Args,
			Env:  envList,
		})
	}
	return result, nil
}

// MCPSTDIOServer defines a local command-based MCP server.
type MCPSTDIOServer struct {
	Name string   `json:"name,omitempty"`
	Args []string `json:"args"`
	Env  []string `json:"env"`
	Cmd  string   `json:"cmd"`
}

// AgentKey returns the namespaced key for an agent: "{userID}:{name}" or just "{name}" if no userID.
func AgentKey(userID, name string) string {
	if userID == "" {
		return name
	}
	return userID + ":" + name
}
