package tools

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/ClareAI/astra-insight-mcp/internal/gateway"
	"github.com/ClareAI/astra-insight-mcp/internal/mcp"
	"github.com/ClareAI/astra-insight-mcp/internal/skills"
)


// RegisterCore registers a minimal set of always-on tools plus skill meta-tools.
// Only ~14 tools are loaded initially; everything else is accessed via skills.
// This keeps the tool-definition token cost low (~2K tokens vs ~6K with all tools).
func RegisterCore(s *mcp.Server, gw *gateway.Client) *skills.Registry {
	// ── Core: Agent CRUD (the essential workflow) ──
	registerListAgents(s, gw)
	registerGetAgent(s, gw)
	registerCreateAgent(s, gw)
	registerUpdateAgent(s, gw)
	registerUpdateInstruction(s, gw)
	registerPublishAgent(s, gw)

	// ── Core: Knowledge (read + annotate) ──
	registerListDocuments(s, gw)
	registerListAnnotations(s, gw)
	registerCreateAnnotation(s, gw)
	registerRetrieveKnowledge(s, gw)

	// ── Core: Quick test ──
	registerSendTestMessage(s, gw)

	// ── Define skills (loaded on demand) ──
	reg := skills.NewRegistry(s, gw)
	defineSkills(reg)

	// ── Skill management meta-tools ──
	registerSkillTools(s, reg)

	return reg
}

// RegisterAll registers every tool at once (no skill system). Used by the CLI agent.
func RegisterAll(s *mcp.Server, gw *gateway.Client) {
	// Read — agent config and setup
	registerListAgents(s, gw)
	registerGetAgent(s, gw)
	registerGetRuntimeConfig(s, gw)
	registerGetBrandkit(s, gw)
	registerFetchBrandkit(s, gw)
	registerCreateBrandkit(s, gw)
	registerUpdateBrandkit(s, gw)
	registerDeleteBrandkit(s, gw)
	registerListActions(s, gw)
	registerGetAction(s, gw)
	registerListConnections(s, gw)

	// Read — knowledge and annotations
	registerListDocuments(s, gw)
	registerListAnnotations(s, gw)
	registerGetAnnotation(s, gw)
	registerRetrieveKnowledge(s, gw)

	// Read — templates
	registerListTemplates(s, gw)
	registerListTemplateCategories(s, gw)
	registerGetTemplate(s, gw)

	// Read — WATI settings
	registerGetWatiSettings(s, gw)

	// Read — performance data
	registerAnalytics(s, gw)
	registerLeadDistribution(s, gw)
	registerListConversations(s, gw)
	registerGetConversation(s, gw)
	registerGetConversationMessages(s, gw)
	registerGetConversationsBatch(s, gw)
	registerGetConversationContact(s, gw)
	registerContacts(s, gw)
	registerGetContact(s, gw)
	registerGetContactConversations(s, gw)

	// Webhooks
	registerListWebhooks(s, gw)
	registerCreateWebhook(s, gw)
	registerUpdateWebhook(s, gw)
	registerDeleteWebhook(s, gw)

	// Write — modify agent
	registerCreateAgent(s, gw)
	registerUpdateAgent(s, gw)
	registerDeleteAgent(s, gw)
	registerUpdateInstruction(s, gw)
	registerPublishAgent(s, gw)
	registerCloneAgent(s, gw)
	registerCreateAnnotation(s, gw)
	registerUpdateAnnotation(s, gw)
	registerDeleteAnnotation(s, gw)
	registerCreateKnowledgeBase(s, gw)
	registerImportKnowledgeURL(s, gw)
	registerImportKnowledgeWebsite(s, gw)
	registerCreateDocument(s, gw)
	registerDeleteDocument(s, gw)

	// Utility
	registerGetImportStatus(s, gw)

	// Integrations (Composio MCP)
	registerIntegrationSkill(s, gw)

	// Test — verify changes
	registerSendTestMessage(s, gw)

	// Testing — pipeline and evaluation
	registerStartTestPipeline(s, gw)
	registerListPipelineJobs(s, gw)
	registerGetPipelineJob(s, gw)
	registerCreateTestSuite(s, gw)
	registerListTestSuites(s, gw)
	registerGetTestSuite(s, gw)
	registerGetTestSuiteProgress(s, gw)
	registerAddTestCase(s, gw)
	registerCreateTestRun(s, gw)
	registerListTestRuns(s, gw)
	registerGetTestRun(s, gw)
	registerCreateRunAnalysis(s, gw)
	registerGetRunAnalysis(s, gw)
	registerAnalyzeFailures(s, gw)
	registerGenerateInstruction(s, gw)
	registerGetAgentTestOverview(s, gw)

	// Voice — agent config
	registerListVoiceAgents(s, gw)
	registerGetVoiceAgent(s, gw)
	registerGetVoiceAgentByTextAgent(s, gw)
	registerGetDefaultTenantVoiceAgents(s, gw)
	registerQuickCreateVoiceAgent(s, gw)
	registerUpdateVoiceAgent(s, gw)
	registerDeleteVoiceAgent(s, gw)
	registerPublishVoiceAgent(s, gw)
	registerGetVoiceAgentCount(s, gw)
	registerCheckVoiceAgentExists(s, gw)

	// Voice — call control and ASR
	registerNewVoiceCall(s, gw)
	registerWebNewVoiceCall(s, gw)
	registerTestNewVoiceCall(s, gw)
	registerTerminateVoiceCall(s, gw)
	registerTestTerminateVoiceCall(s, gw)
	registerInitiateOutboundCall(s, gw)
	registerGetWebRTCConfig(s, gw)
	registerASRTranscribe(s, gw)

	// Voice — minimax clone
	registerUploadUserVoice(s, gw)
	registerListMinimaxVoices(s, gw)
	registerGetMinimaxVoice(s, gw)
	registerUpdateMinimaxVoice(s, gw)
	registerSubmitVoiceClone(s, gw)
	registerSearchVoiceLibrary(s, gw)
	registerSearchCollectedVoices(s, gw)
}

// ── Skill definitions ──

func defineSkills(reg *skills.Registry) {
	reg.Define("branding", "Brand kit management — fetch from domain, create, update, and delete brand kits for agents.", []string{
		"get_brandkit", "fetch_brandkit", "create_brandkit", "update_brandkit", "delete_brandkit",
	}, registerBrandingSkill)

	reg.Define("conversations", "Conversation & contact analysis — browse conversations, read messages, and inspect contacts. Use get_conversations_batch to fetch multiple conversations with messages in one call.", []string{
		"list_conversations", "get_conversation", "get_conversation_messages",
		"get_conversations_batch",
		"get_conversation_contact", "get_contacts_and_leads", "get_contact",
		"get_contact_conversations",
	}, registerConversationsSkill)

	reg.Define("agent_setup", "Extended agent setup — runtime config, cloning, deletion, actions, and connections.", []string{
		"get_runtime_config", "clone_agent", "delete_agent",
		"list_actions", "get_action", "list_connections",
	}, registerAgentSetupSkill)

	reg.DefineWithContext("knowledge_management",
		"Full knowledge & annotation CRUD — create KB, import from URL/website, manage documents and FAQ overrides. Includes expert context on KB workflows and known backend issues.",
		[]string{
			"get_annotation", "update_annotation", "delete_annotation",
			"create_knowledge_base", "create_knowledge_document", "delete_knowledge_document",
			"import_knowledge_from_url", "import_knowledge_from_website",
			"get_import_status",
		}, registerKnowledgeManagementSkill,
		readSkillFile("knowledge-management.md"),
	)

	reg.Define("analytics", "Deep analytics — unified metrics, lead score distribution, and conversation trends.", []string{
		"get_analytics", "get_lead_distribution",
	}, registerAnalyticsSkill)

	reg.DefineWithContext("testing",
		"Systematic test pipeline — generate test cases, execute, evaluate, and analyze failures. Includes expert context on instruction optimization and testing workflows.",
		[]string{
			"start_test_pipeline", "list_pipeline_jobs", "get_pipeline_job",
			"create_test_suite", "list_test_suites", "get_test_suite",
			"get_test_suite_progress", "add_test_case",
			"create_test_run", "list_test_runs", "get_test_run",
			"create_run_analysis", "get_run_analysis",
			"analyze_failures", "generate_instruction",
			"get_agent_test_overview",
		}, registerTestingSkill,
		readSkillFile("instruction-optimization.md"),
	)

	reg.Define("templates", "Browse and inspect pre-built agent templates by category.", []string{
		"list_templates", "list_template_categories", "get_template",
	}, registerTemplatesSkill)

	reg.Define("webhooks", "Webhook CRUD — register URLs to receive real-time event notifications.", []string{
		"list_webhooks", "create_webhook", "update_webhook", "delete_webhook",
	}, registerWebhooksSkill)

	reg.Define("integrations", "Composio MCP integrations — manage platform connections (Slack, HubSpot, Salesforce, Google Sheets, Zoho, WATI, etc.), browse action templates, create/delete integrations, OAuth auth flow, and register/deregister tools with agents. Also includes WATI settings retrieval.", []string{
		"get_integration_platforms", "list_integration_templates",
		"list_agent_integrations", "list_configured_integrations", "get_configured_integration",
		"create_integration", "delete_integration",
		"create_integration_auth", "wait_integration_auth", "get_integration_auth",
		"create_connection", "get_wati_settings",
		"register_agent_integrations", "deregister_agent_integrations",
	}, registerIntegrationSkill)

	// ── Voice skills ──

	reg.DefineWithContext("voice_agent",
		"Voice agent management — quick-create from templates, read/update/delete/publish voice agents. Includes expert context on voice agent workflows and config fields.",
		[]string{
			"list_voice_agents", "get_voice_agent", "get_voice_agent_by_text_agent",
			"get_default_tenant_voice_agents", "quick_create_voice_agent",
			"update_voice_agent", "delete_voice_agent", "publish_voice_agent",
			"get_voice_agent_count", "check_voice_agent_exists",
		}, registerVoiceAgentSkill,
		readSkillFile("voice-agent.md"),
	)

	reg.Define("voice_calls",
		"Voice call control and ASR — initiate/terminate WhatsApp and web voice calls, test calls, outbound calls, WebRTC config, and speech-to-text transcription.",
		[]string{
			"new_voice_call", "web_new_voice_call", "test_new_voice_call",
			"terminate_voice_call", "test_terminate_voice_call",
			"initiate_outbound_call", "get_webrtc_config",
			"asr_transcribe",
		}, registerVoiceCallsSkill,
	)

	reg.Define("voice_clone",
		"Minimax voice clone — upload user voice audio, submit clones, list/manage voices, search the voice library.",
		[]string{
			"upload_user_voice", "submit_voice_clone",
			"list_minimax_voices", "get_minimax_voice", "update_minimax_voice",
			"search_voice_library", "search_collected_voices",
		}, registerVoiceCloneSkill,
	)

	// Knowledge-only skills — no tools, just expert context loaded on demand.
	noop := func(*mcp.Server, *gateway.Client) {}

	reg.DefineWithContext("agent_creation_guide",
		"Expert workflow guide for creating agents end-to-end — correct order, gotchas, KB binding, brandkit, publishing.",
		nil, noop,
		readSkillFile("agent-creation.md"),
	)

	reg.DefineWithContext("debugging_guide",
		"Troubleshooting reference — common API errors (400/422/500), known backend issues, efficiency tips.",
		nil, noop,
		readSkillFile("debugging-tips.md"),
	)
}

// readSkillFile reads a single markdown file from the skills/ directory.
func readSkillFile(filename string) string {
	candidates := []string{"skills", "../skills", "/skills"}
	if exe, err := os.Executable(); err == nil {
		candidates = append(candidates, filepath.Join(filepath.Dir(exe), "skills"))
	}
	for _, dir := range candidates {
		path := filepath.Join(dir, filename)
		data, err := os.ReadFile(path)
		if err == nil {
			return strings.TrimSpace(string(data))
		}
	}
	return ""
}

func registerBrandingSkill(s *mcp.Server, gw *gateway.Client) {
	registerGetBrandkit(s, gw)
	registerFetchBrandkit(s, gw)
	registerCreateBrandkit(s, gw)
	registerUpdateBrandkit(s, gw)
	registerDeleteBrandkit(s, gw)
}

func registerConversationsSkill(s *mcp.Server, gw *gateway.Client) {
	registerListConversations(s, gw)
	registerGetConversation(s, gw)
	registerGetConversationMessages(s, gw)
	registerGetConversationsBatch(s, gw)
	registerGetConversationContact(s, gw)
	registerContacts(s, gw)
	registerGetContact(s, gw)
	registerGetContactConversations(s, gw)
}

func registerAgentSetupSkill(s *mcp.Server, gw *gateway.Client) {
	registerGetRuntimeConfig(s, gw)
	registerCloneAgent(s, gw)
	registerDeleteAgent(s, gw)
	registerListActions(s, gw)
	registerGetAction(s, gw)
	registerListConnections(s, gw)
}

func registerTestingSkill(s *mcp.Server, gw *gateway.Client) {
	registerStartTestPipeline(s, gw)
	registerListPipelineJobs(s, gw)
	registerGetPipelineJob(s, gw)
	registerCreateTestSuite(s, gw)
	registerListTestSuites(s, gw)
	registerGetTestSuite(s, gw)
	registerGetTestSuiteProgress(s, gw)
	registerAddTestCase(s, gw)
	registerCreateTestRun(s, gw)
	registerListTestRuns(s, gw)
	registerGetTestRun(s, gw)
	registerCreateRunAnalysis(s, gw)
	registerGetRunAnalysis(s, gw)
	registerAnalyzeFailures(s, gw)
	registerGenerateInstruction(s, gw)
	registerGetAgentTestOverview(s, gw)
}

func registerAnalyticsSkill(s *mcp.Server, gw *gateway.Client) {
	registerAnalytics(s, gw)
	registerLeadDistribution(s, gw)
}

func registerKnowledgeManagementSkill(s *mcp.Server, gw *gateway.Client) {
	registerGetAnnotation(s, gw)
	registerUpdateAnnotation(s, gw)
	registerDeleteAnnotation(s, gw)
	registerCreateKnowledgeBase(s, gw)
	registerCreateDocument(s, gw)
	registerDeleteDocument(s, gw)
	registerImportKnowledgeURL(s, gw)
	registerImportKnowledgeWebsite(s, gw)
	registerGetImportStatus(s, gw)
}

func registerTemplatesSkill(s *mcp.Server, gw *gateway.Client) {
	registerListTemplates(s, gw)
	registerListTemplateCategories(s, gw)
	registerGetTemplate(s, gw)
}

func registerWebhooksSkill(s *mcp.Server, gw *gateway.Client) {
	registerListWebhooks(s, gw)
	registerCreateWebhook(s, gw)
	registerUpdateWebhook(s, gw)
	registerDeleteWebhook(s, gw)
}

func registerVoiceAgentSkill(s *mcp.Server, gw *gateway.Client) {
	registerListVoiceAgents(s, gw)
	registerGetVoiceAgent(s, gw)
	registerGetVoiceAgentByTextAgent(s, gw)
	registerGetDefaultTenantVoiceAgents(s, gw)
	registerQuickCreateVoiceAgent(s, gw)
	registerUpdateVoiceAgent(s, gw)
	registerDeleteVoiceAgent(s, gw)
	registerPublishVoiceAgent(s, gw)
	registerGetVoiceAgentCount(s, gw)
	registerCheckVoiceAgentExists(s, gw)
}

func registerVoiceCallsSkill(s *mcp.Server, gw *gateway.Client) {
	registerNewVoiceCall(s, gw)
	registerWebNewVoiceCall(s, gw)
	registerTestNewVoiceCall(s, gw)
	registerTerminateVoiceCall(s, gw)
	registerTestTerminateVoiceCall(s, gw)
	registerInitiateOutboundCall(s, gw)
	registerGetWebRTCConfig(s, gw)
	registerASRTranscribe(s, gw)
}

func registerVoiceCloneSkill(s *mcp.Server, gw *gateway.Client) {
	registerUploadUserVoice(s, gw)
	registerListMinimaxVoices(s, gw)
	registerGetMinimaxVoice(s, gw)
	registerUpdateMinimaxVoice(s, gw)
	registerSubmitVoiceClone(s, gw)
	registerSearchVoiceLibrary(s, gw)
	registerSearchCollectedVoices(s, gw)
}

// ── Skill management meta-tools ──

func registerSkillTools(s *mcp.Server, reg *skills.Registry) {
	s.RegisterTool(mcp.Tool{
		Name:        "list_skills",
		Description: "List available tool skills and their activation status. Skills are groups of related tools that can be activated on demand to keep the tool list focused. Call this first to see what's available.",
		InputSchema: mcp.InputSchema{
			Type:       "object",
			Properties: map[string]mcp.Property{},
		},
	}, func(_ context.Context, _ map[string]interface{}) (interface{}, error) {
		return reg.List(), nil
	})

	s.RegisterTool(mcp.Tool{
		Name:        "activate_skill",
		Description: "Activate a skill to register its tools. After activation, the skill's tools become available for use. Call list_skills first to see available skills.",
		InputSchema: mcp.InputSchema{
			Type: "object",
			Properties: map[string]mcp.Property{
				"name": {Type: "string", Description: "Skill name to activate"},
			},
			Required: []string{"name"},
		},
	}, func(_ context.Context, args map[string]interface{}) (interface{}, error) {
		name, _ := args["name"].(string)
		if name == "" {
			return nil, fmt.Errorf("name is required")
		}
		expertCtx, err := reg.Activate(name)
		if err != nil {
			return nil, err
		}
		info := reg.List()
		for _, sk := range info {
			if sk.Name == name {
				result := map[string]interface{}{
					"status":  "activated",
					"skill":   sk.Name,
					"tools":   sk.Tools,
					"message": fmt.Sprintf("Skill %q activated — %d tools now available.", name, sk.ToolCount),
				}
				if expertCtx != "" {
					result["expert_context"] = expertCtx
				}
				return result, nil
			}
		}
		result := map[string]interface{}{"status": "activated", "skill": name}
		if expertCtx != "" {
			result["expert_context"] = expertCtx
		}
		return result, nil
	})

	s.RegisterTool(mcp.Tool{
		Name:        "deactivate_skill",
		Description: "Deactivate a skill to remove its tools. Use this to reduce tool clutter when you're done with a skill.",
		InputSchema: mcp.InputSchema{
			Type: "object",
			Properties: map[string]mcp.Property{
				"name": {Type: "string", Description: "Skill name to deactivate"},
			},
			Required: []string{"name"},
		},
	}, func(_ context.Context, args map[string]interface{}) (interface{}, error) {
		name, _ := args["name"].(string)
		if name == "" {
			return nil, fmt.Errorf("name is required")
		}
		if err := reg.Deactivate(name); err != nil {
			return nil, err
		}
		return map[string]string{
			"status":  "deactivated",
			"skill":   name,
			"message": fmt.Sprintf("Skill %q deactivated — its tools have been removed.", name),
		}, nil
	})
}
