package dispatcher

import (
	"strings"

	"github.com/tidbcloud/AgentTeam/desktop/internal/agent"
	"github.com/tidbcloud/AgentTeam/desktop/internal/agent/runtimeconfig"
	"github.com/tidbcloud/AgentTeam/desktop/internal/promptcompiler"
	"github.com/tidbcloud/AgentTeam/desktop/internal/types"
	"github.com/tidbcloud/AgentTeam/desktop/internal/workspace"
)

func toolNamePrefix(rt runtimeconfig.RuntimeType, namespace string) types.ToolNamer {
	namespace = strings.TrimSpace(namespace)
	if namespace == "" {
		namespace = "agentteam"
	}
	var prefix string
	switch runtimeconfig.EffectiveRuntimeType(rt) {
	case runtimeconfig.TypeClaudeCode, runtimeconfig.TypeCodex, runtimeconfig.TypeKimi, runtimeconfig.TypePi:
		prefix = "mcp__" + namespace + "__"
	default:
		prefix = "mcp_" + namespace + "_"
	}
	return func(name string) string {
		return prefix + strings.TrimSpace(name)
	}
}

func instructionsFingerprint(baseInstructions, developerInstructions string) string {
	return promptcompiler.InstructionFingerprint(baseInstructions, developerInstructions)
}

// codexAppServerInstructionsFingerprintVersion identifies the instruction
// fingerprint representation used by the Codex app-server contract. It is a
// representation version, not a provider/MCP wiring fingerprint.
const codexAppServerInstructionsFingerprintVersion = "codex-app-server-instructions-v1"

// codexAppServerMCPFingerprintMarker is retained only to decode fingerprints
// written by older daemons. MCP endpoint, command, argument, CWD, and tool
// changes are runtime wiring changes and are not provider-session guards.
const codexAppServerMCPFingerprintMarker = ":mcp:"

func codexAppServerInstructionsFingerprint(baseInstructions, developerInstructions string) string {
	return codexAppServerInstructionsFingerprintFromFingerprint(instructionsFingerprint(baseInstructions, developerInstructions))
}

// codexAppServerSessionFingerprint is a compatibility-named wrapper. The
// current value contains only the semantic base/developer instruction
// fingerprint; mcps is deliberately ignored. Older state may contain an
// appended :mcp:<hash> suffix, which is normalized when comparing state.
func codexAppServerSessionFingerprint(fingerprint string, _ []types.NamedMCPConfig) string {
	return codexAppServerInstructionsFingerprintFromFingerprint(fingerprint)
}

// codexAppServerVersionedInstructionsFingerprint is retained for callers
// that used the pre-MCP helper name; it now versions instructions only.
func codexAppServerVersionedInstructionsFingerprint(fingerprint string) string {
	return codexAppServerInstructionsFingerprintFromFingerprint(fingerprint)
}

func codexAppServerInstructionsFingerprintFromFingerprint(fingerprint string) string {
	fingerprint = strings.TrimSpace(fingerprint)
	if fingerprint == "" {
		return ""
	}
	return fingerprint + ":" + codexAppServerInstructionsFingerprintVersion
}

func normalizeCodexAppServerInstructionsFingerprint(fingerprint string) string {
	fingerprint = strings.TrimSpace(fingerprint)
	if fingerprint == "" {
		return ""
	}
	// A legacy daemon appended the MCP configuration after this marker. Strip only
	// that known suffix; the prefix remains the instruction fingerprint.
	if marker := strings.Index(fingerprint, codexAppServerMCPFingerprintMarker); marker >= 0 {
		fingerprint = fingerprint[:marker]
	}
	fingerprint = strings.TrimSuffix(fingerprint, ":"+codexAppServerInstructionsFingerprintVersion)
	// Older Codex state used the dynamic-tool version marker. It represented
	// the old storage strategy rather than instruction content, so accept it
	// after the MCP suffix has been removed.
	fingerprint = strings.TrimSuffix(fingerprint, ":codex-app-server-dynamic-tools-v2")
	return strings.TrimSpace(fingerprint)
}

func codexAppServerInstructionsFingerprintMatches(saved, current string) bool {
	saved = normalizeCodexAppServerInstructionsFingerprint(saved)
	current = normalizeCodexAppServerInstructionsFingerprint(current)
	return saved != "" && current != "" && saved == current
}

// initMemoryMD creates the initial MEMORY.md file and local memory layout for a new agent session.
func initMemoryMD(workDir, agentID string, ag agent.Config) (workspace.MemoryLayoutReport, error) {
	name := strings.TrimSpace(ag.Name)
	if name == "" {
		name = agentID
	}
	return workspace.InitializeMemoryLayoutWithReport(workDir, name)
}
