package server

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"sync"
	"sync/atomic"
	"time"

	"github.com/CalmoAI/mcp-server-signoz/internal/domain"
	"github.com/CalmoAI/mcp-server-signoz/pkg/mcp"
	"github.com/CalmoAI/mcp-server-signoz/pkg/mcp/transport"
)

// Server implements the MCP server
type Server struct {
	info         mcp.ServerInfo
	capabilities mcp.ServerCapabilities
	transport    mcp.Transport
	mcpService   domain.MCPService
	logger       domain.Logger
	tracer       domain.Tracer
	metrics      domain.Metrics

	// State management
	initialized bool
	mu          sync.RWMutex
	requestID   int64

	// Tool definitions
	tools map[string]mcp.Tool

	// Context for graceful shutdown
	ctx    context.Context
	cancel context.CancelFunc
}

// NewServer creates a new MCP server
func NewServer(
	transport mcp.Transport,
	mcpService domain.MCPService,
	logger domain.Logger,
	tracer domain.Tracer,
	metrics domain.Metrics,
) *Server {
	ctx, cancel := context.WithCancel(context.Background())

	server := &Server{
		info: mcp.ServerInfo{
			Name:    "signoz-mcp-server",
			Version: "1.0.0",
		},
		capabilities: mcp.ServerCapabilities{
			Tools: &mcp.ToolsCapability{
				ListChanged: false,
			},
		},
		transport:  transport,
		mcpService: mcpService,
		logger:     logger,
		tracer:     tracer,
		metrics:    metrics,
		ctx:        ctx,
		cancel:     cancel,
		tools:      make(map[string]mcp.Tool),
	}

	// Register all tools
	server.registerTools()

	return server
}

// Run starts the MCP server
func (s *Server) Run() error {
	s.logger.Info("starting MCP server",
		domain.Field{Key: "server", Value: s.info.Name},
		domain.Field{Key: "version", Value: s.info.Version},
	)

	// Start processing messages
	for {
		select {
		case <-s.ctx.Done():
			s.logger.Info("shutting down MCP server")
			return s.ctx.Err()
		default:
			// Add a small timeout to prevent hanging
			message, err := s.transport.Receive()
			if err != nil {
				if err == io.EOF {
					s.logger.Info("received EOF, shutting down gracefully")
					return nil
				}
				s.logger.Error("failed to receive message",
					domain.Field{Key: "error", Value: err.Error()},
				)
				// Add a small delay to prevent tight error loops
				time.Sleep(100 * time.Millisecond)
				continue
			}

			if message == nil {
				continue
			}

			// Handle message synchronously to ensure response is sent before reading next message
			s.handleMessage(message)
		}
	}
}

// Shutdown gracefully shuts down the server
func (s *Server) Shutdown() error {
	s.logger.Info("shutting down MCP server")
	s.cancel()
	return s.transport.Close()
}

// handleMessage processes incoming MCP messages
func (s *Server) handleMessage(message *mcp.MCPMessage) {
	ctx := s.ctx
	if message.ID != nil {
		ctx = context.WithValue(ctx, mcp.ContextKeyRequestID, *message.ID)
	}

	ctx, span := s.tracer.StartSpan(ctx, "mcp.handle_message")
	defer span.End()

	span.SetAttribute("method", message.Method)
	if message.ID != nil {
		span.SetAttribute("request_id", *message.ID)
	}

	s.logger.Debug("handling MCP message",
		domain.Field{Key: "method", Value: message.Method},
		domain.Field{Key: "has_id", Value: message.ID != nil},
	)

	// Record metrics
	counter := s.metrics.Counter("mcp_messages_total")
	counter.Add(ctx, 1, domain.Attribute{Key: "method", Value: message.Method})

	var response *mcp.MCPMessage
	var err error

	switch message.Method {
	case "initialize":
		response, err = s.handleInitialize(ctx, message)
	case "tools/list":
		response, err = s.handleToolsList(ctx, message)
	case "tools/call":
		response, err = s.handleToolsCall(ctx, message)
	case "":
		// This might be a response, ignore
		return
	default:
		err = fmt.Errorf("unknown method: %s", message.Method)
	}

	if err != nil {
		span.SetStatus(domain.StatusCodeError, err.Error())
		span.RecordError(err)
		s.logger.Error("error handling message",
			domain.Field{Key: "method", Value: message.Method},
			domain.Field{Key: "error", Value: err.Error()},
		)

		if message.ID != nil {
			response = transport.NewMessageBuilder().
				Response(*message.ID).
				WithError(mcp.ErrorCodeInternalError, err.Error(), nil).
				Build()
		}
	}

	if response != nil {
		if err := s.transport.Send(response); err != nil {
			s.logger.Error("failed to send response",
				domain.Field{Key: "error", Value: err.Error()},
			)
		}
	}
}

// handleInitialize handles the initialize request
func (s *Server) handleInitialize(ctx context.Context, message *mcp.MCPMessage) (*mcp.MCPMessage, error) {
	if message.ID == nil {
		return nil, fmt.Errorf("initialize request must have an ID")
	}

	var request mcp.InitializeRequest
	if err := json.Unmarshal(message.Params, &request); err != nil {
		return nil, fmt.Errorf("invalid initialize request: %w", err)
	}

	s.logger.Info("received initialize request",
		domain.Field{Key: "protocol_version", Value: request.ProtocolVersion},
		domain.Field{Key: "client", Value: request.ClientInfo.Name},
		domain.Field{Key: "client_version", Value: request.ClientInfo.Version},
	)

	// Check protocol version compatibility
	if request.ProtocolVersion != mcp.MCPVersion {
		return nil, fmt.Errorf("unsupported protocol version: %s", request.ProtocolVersion)
	}

	s.mu.Lock()
	s.initialized = true
	s.mu.Unlock()

	response := mcp.InitializeResponse{
		ProtocolVersion: mcp.MCPVersion,
		Capabilities:    s.capabilities,
		ServerInfo:      s.info,
	}

	return transport.NewMessageBuilder().
		Response(*message.ID).
		WithResult(response).
		Build(), nil
}

// handleToolsList handles the tools/list request
func (s *Server) handleToolsList(ctx context.Context, message *mcp.MCPMessage) (*mcp.MCPMessage, error) {
	if message.ID == nil {
		return nil, fmt.Errorf("tools/list request must have an ID")
	}

	s.mu.RLock()
	if !s.initialized {
		s.mu.RUnlock()
		return nil, fmt.Errorf("server not initialized")
	}
	s.mu.RUnlock()

	var request mcp.ToolsListRequest
	if message.Params != nil {
		if err := json.Unmarshal(message.Params, &request); err != nil {
			return nil, fmt.Errorf("invalid tools/list request: %w", err)
		}
	}

	tools := make([]mcp.Tool, 0, len(s.tools))
	for _, tool := range s.tools {
		tools = append(tools, tool)
	}

	response := mcp.ToolsListResponse{
		Tools: tools,
	}

	s.logger.Debug("returning tools list",
		domain.Field{Key: "tool_count", Value: len(tools)},
	)

	return transport.NewMessageBuilder().
		Response(*message.ID).
		WithResult(response).
		Build(), nil
}

// handleToolsCall handles the tools/call request
func (s *Server) handleToolsCall(ctx context.Context, message *mcp.MCPMessage) (*mcp.MCPMessage, error) {
	if message.ID == nil {
		return nil, fmt.Errorf("tools/call request must have an ID")
	}

	s.mu.RLock()
	if !s.initialized {
		s.mu.RUnlock()
		return nil, fmt.Errorf("server not initialized")
	}
	s.mu.RUnlock()

	var request mcp.ToolsCallRequest
	if err := json.Unmarshal(message.Params, &request); err != nil {
		return nil, fmt.Errorf("invalid tools/call request: %w", err)
	}

	ctx, span := s.tracer.StartSpan(ctx, "mcp.tool_call")
	defer span.End()

	span.SetAttribute("tool_name", request.Name)

	s.logger.Info("executing tool",
		domain.Field{Key: "tool", Value: request.Name},
	)

	// Record metrics
	counter := s.metrics.Counter("mcp_tool_executions_total")
	counter.Add(ctx, 1, domain.Attribute{Key: "tool", Value: request.Name})

	histogram := s.metrics.Histogram("mcp_tool_execution_duration_seconds")
	start := time.Now()
	defer func() {
		duration := time.Since(start).Seconds()
		histogram.Record(ctx, duration, domain.Attribute{Key: "tool", Value: request.Name})
	}()

	// Execute the tool
	result, err := s.executeTool(ctx, request.Name, request.Arguments)
	if err != nil {
		span.SetStatus(domain.StatusCodeError, err.Error())
		span.RecordError(err)

		errorCounter := s.metrics.Counter("mcp_tool_errors_total")
		errorCounter.Add(ctx, 1, domain.Attribute{Key: "tool", Value: request.Name})

		s.logger.Error("tool execution failed",
			domain.Field{Key: "tool", Value: request.Name},
			domain.Field{Key: "error", Value: err.Error()},
		)

		response := mcp.ToolsCallResponse{
			Content: []mcp.Content{
				{
					Type: string(mcp.ContentTypeText),
					Text: fmt.Sprintf("Error executing tool %s: %s", request.Name, err.Error()),
				},
			},
			IsError: true,
		}

		return transport.NewMessageBuilder().
			Response(*message.ID).
			WithResult(response).
			Build(), nil
	}

	s.logger.Info("tool executed successfully",
		domain.Field{Key: "tool", Value: request.Name},
	)

	return transport.NewMessageBuilder().
		Response(*message.ID).
		WithResult(result).
		Build(), nil
}

// executeTool executes a specific tool with the given arguments
func (s *Server) executeTool(ctx context.Context, toolName string, arguments map[string]interface{}) (mcp.ToolsCallResponse, error) {
	switch toolName {
	case "signoz_test_connection":
		return s.executeTestConnection(ctx)
	case "signoz_fetch_dashboards":
		return s.executeFetchDashboards(ctx)
	case "signoz_fetch_dashboard_details":
		return s.executeFetchDashboardDetails(ctx, arguments)
	case "signoz_fetch_dashboard_data":
		return s.executeFetchDashboardData(ctx, arguments)
	case "signoz_fetch_apm_metrics":
		return s.executeFetchAPMMetrics(ctx, arguments)
	case "signoz_fetch_services":
		return s.executeFetchServices(ctx, arguments)
	case "signoz_execute_clickhouse_query":
		return s.executeClickHouseQuery(ctx, arguments)
	case "signoz_execute_builder_query":
		return s.executeBuilderQuery(ctx, arguments)
	case "signoz_fetch_traces_or_logs":
		return s.executeFetchTracesOrLogs(ctx, arguments)
	default:
		return mcp.ToolsCallResponse{}, fmt.Errorf("unknown tool: %s", toolName)
	}
}

// executeTestConnection executes the signoz_test_connection tool
func (s *Server) executeTestConnection(ctx context.Context) (mcp.ToolsCallResponse, error) {
	status, err := s.mcpService.TestConnection(ctx)
	if err != nil {
		return mcp.ToolsCallResponse{}, err
	}

	result, err := json.MarshalIndent(status, "", "  ")
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("failed to marshal result: %w", err)
	}

	return mcp.ToolsCallResponse{
		Content: []mcp.Content{
			{
				Type: string(mcp.ContentTypeText),
				Text: string(result),
			},
		},
	}, nil
}

// executeFetchDashboards executes the signoz_fetch_dashboards tool
func (s *Server) executeFetchDashboards(ctx context.Context) (mcp.ToolsCallResponse, error) {
	dashboards, err := s.mcpService.FetchDashboards(ctx)
	if err != nil {
		return mcp.ToolsCallResponse{}, err
	}

	result, err := json.MarshalIndent(dashboards, "", "  ")
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("failed to marshal result: %w", err)
	}

	return mcp.ToolsCallResponse{
		Content: []mcp.Content{
			{
				Type: string(mcp.ContentTypeText),
				Text: string(result),
			},
		},
	}, nil
}

// executeFetchDashboardDetails executes the signoz_fetch_dashboard_details tool
func (s *Server) executeFetchDashboardDetails(ctx context.Context, arguments map[string]interface{}) (mcp.ToolsCallResponse, error) {
	dashboardID, ok := arguments["dashboard_id"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("dashboard_id is required and must be a string")
	}

	dashboard, err := s.mcpService.FetchDashboardDetails(ctx, dashboardID)
	if err != nil {
		return mcp.ToolsCallResponse{}, err
	}

	result, err := json.MarshalIndent(dashboard, "", "  ")
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("failed to marshal result: %w", err)
	}

	return mcp.ToolsCallResponse{
		Content: []mcp.Content{
			{
				Type: string(mcp.ContentTypeText),
				Text: string(result),
			},
		},
	}, nil
}

// executeFetchDashboardData executes the signoz_fetch_dashboard_data tool
func (s *Server) executeFetchDashboardData(ctx context.Context, arguments map[string]interface{}) (mcp.ToolsCallResponse, error) {
	dashboardName, ok := arguments["dashboard_name"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("dashboard_name is required and must be a string")
	}

	startTimeStr, ok := arguments["start_time"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("start_time is required and must be a string")
	}

	endTimeStr, ok := arguments["end_time"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("end_time is required and must be a string")
	}

	startTime, err := time.Parse(time.RFC3339, startTimeStr)
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("invalid start_time format: %w", err)
	}

	endTime, err := time.Parse(time.RFC3339, endTimeStr)
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("invalid end_time format: %w", err)
	}

	data, err := s.mcpService.FetchDashboardData(ctx, dashboardName, startTime, endTime)
	if err != nil {
		return mcp.ToolsCallResponse{}, err
	}

	result, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("failed to marshal result: %w", err)
	}

	return mcp.ToolsCallResponse{
		Content: []mcp.Content{
			{
				Type: string(mcp.ContentTypeText),
				Text: string(result),
			},
		},
	}, nil
}

// executeFetchAPMMetrics executes the signoz_fetch_apm_metrics tool
func (s *Server) executeFetchAPMMetrics(ctx context.Context, arguments map[string]interface{}) (mcp.ToolsCallResponse, error) {
	serviceName, ok := arguments["service_name"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("service_name is required and must be a string")
	}

	startTimeStr, ok := arguments["start_time"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("start_time is required and must be a string")
	}

	endTimeStr, ok := arguments["end_time"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("end_time is required and must be a string")
	}

	startTime, err := time.Parse(time.RFC3339, startTimeStr)
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("invalid start_time format: %w", err)
	}

	endTime, err := time.Parse(time.RFC3339, endTimeStr)
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("invalid end_time format: %w", err)
	}

	metrics, err := s.mcpService.FetchAPMMetrics(ctx, serviceName, startTime, endTime)
	if err != nil {
		return mcp.ToolsCallResponse{}, err
	}

	result, err := json.MarshalIndent(metrics, "", "  ")
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("failed to marshal result: %w", err)
	}

	return mcp.ToolsCallResponse{
		Content: []mcp.Content{
			{
				Type: string(mcp.ContentTypeText),
				Text: string(result),
			},
		},
	}, nil
}

// executeFetchServices executes the signoz_fetch_services tool
func (s *Server) executeFetchServices(ctx context.Context, arguments map[string]interface{}) (mcp.ToolsCallResponse, error) {
	var startTime, endTime *time.Time

	if startTimeStr, ok := arguments["start_time"].(string); ok && startTimeStr != "" {
		t, err := time.Parse(time.RFC3339, startTimeStr)
		if err != nil {
			return mcp.ToolsCallResponse{}, fmt.Errorf("invalid start_time format: %w", err)
		}
		startTime = &t
	}

	if endTimeStr, ok := arguments["end_time"].(string); ok && endTimeStr != "" {
		t, err := time.Parse(time.RFC3339, endTimeStr)
		if err != nil {
			return mcp.ToolsCallResponse{}, fmt.Errorf("invalid end_time format: %w", err)
		}
		endTime = &t
	}

	services, err := s.mcpService.FetchServices(ctx, startTime, endTime)
	if err != nil {
		return mcp.ToolsCallResponse{}, err
	}

	result, err := json.MarshalIndent(services, "", "  ")
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("failed to marshal result: %w", err)
	}

	return mcp.ToolsCallResponse{
		Content: []mcp.Content{
			{
				Type: string(mcp.ContentTypeText),
				Text: string(result),
			},
		},
	}, nil
}

// executeClickHouseQuery executes the signoz_execute_clickhouse_query tool
func (s *Server) executeClickHouseQuery(ctx context.Context, arguments map[string]interface{}) (mcp.ToolsCallResponse, error) {
	sql, ok := arguments["sql"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("sql is required and must be a string")
	}

	startTimeStr, ok := arguments["start_time"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("start_time is required and must be a string")
	}

	endTimeStr, ok := arguments["end_time"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("end_time is required and must be a string")
	}

	startTime, err := time.Parse(time.RFC3339, startTimeStr)
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("invalid start_time format: %w", err)
	}

	endTime, err := time.Parse(time.RFC3339, endTimeStr)
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("invalid end_time format: %w", err)
	}

	params, _ := arguments["params"].(map[string]interface{})

	result, err := s.mcpService.ExecuteClickHouseQuery(ctx, sql, startTime, endTime, params)
	if err != nil {
		return mcp.ToolsCallResponse{}, err
	}

	resultJSON, err := json.MarshalIndent(result, "", "  ")
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("failed to marshal result: %w", err)
	}

	return mcp.ToolsCallResponse{
		Content: []mcp.Content{
			{
				Type: string(mcp.ContentTypeText),
				Text: string(resultJSON),
			},
		},
	}, nil
}

// executeBuilderQuery executes the signoz_execute_builder_query tool
func (s *Server) executeBuilderQuery(ctx context.Context, arguments map[string]interface{}) (mcp.ToolsCallResponse, error) {
	queryType, ok := arguments["query_type"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("query_type is required and must be a string")
	}

	metricName, ok := arguments["metric_name"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("metric_name is required and must be a string")
	}

	aggregation, ok := arguments["aggregation"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("aggregation is required and must be a string")
	}

	startTimeStr, ok := arguments["start_time"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("start_time is required and must be a string")
	}

	endTimeStr, ok := arguments["end_time"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("end_time is required and must be a string")
	}

	startTime, err := time.Parse(time.RFC3339, startTimeStr)
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("invalid start_time format: %w", err)
	}

	endTime, err := time.Parse(time.RFC3339, endTimeStr)
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("invalid end_time format: %w", err)
	}

	// Parse optional parameters
	var filters []domain.QueryFilter
	if filtersRaw, ok := arguments["filters"].([]interface{}); ok {
		for _, f := range filtersRaw {
			if filterMap, ok := f.(map[string]interface{}); ok {
				filter := domain.QueryFilter{
					Key:      filterMap["key"].(string),
					Operator: filterMap["operator"].(string),
					Value:    filterMap["value"],
				}
				filters = append(filters, filter)
			}
		}
	}

	var groupBy []string
	if groupByRaw, ok := arguments["group_by"].([]interface{}); ok {
		for _, gb := range groupByRaw {
			if gbStr, ok := gb.(string); ok {
				groupBy = append(groupBy, gbStr)
			}
		}
	}

	step := 60 * time.Second // Default step
	if stepStr, ok := arguments["step"].(string); ok {
		if parsedStep, err := time.ParseDuration(stepStr); err == nil {
			step = parsedStep
		}
	}

	options, _ := arguments["options"].(map[string]interface{})

	result, err := s.mcpService.ExecuteBuilderQuery(ctx, queryType, metricName, aggregation, filters, groupBy, startTime, endTime, step, options)
	if err != nil {
		return mcp.ToolsCallResponse{}, err
	}

	resultJSON, err := json.MarshalIndent(result, "", "  ")
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("failed to marshal result: %w", err)
	}

	return mcp.ToolsCallResponse{
		Content: []mcp.Content{
			{
				Type: string(mcp.ContentTypeText),
				Text: string(resultJSON),
			},
		},
	}, nil
}

// executeFetchTracesOrLogs executes the signoz_fetch_traces_or_logs tool
func (s *Server) executeFetchTracesOrLogs(ctx context.Context, arguments map[string]interface{}) (mcp.ToolsCallResponse, error) {
	dataType, ok := arguments["data_type"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("data_type is required and must be a string")
	}

	serviceName, ok := arguments["service_name"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("service_name is required and must be a string")
	}

	startTimeStr, ok := arguments["start_time"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("start_time is required and must be a string")
	}

	endTimeStr, ok := arguments["end_time"].(string)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("end_time is required and must be a string")
	}

	limitFloat, ok := arguments["limit"].(float64)
	if !ok {
		return mcp.ToolsCallResponse{}, fmt.Errorf("limit is required and must be a number")
	}
	limit := int(limitFloat)

	startTime, err := time.Parse(time.RFC3339, startTimeStr)
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("invalid start_time format: %w", err)
	}

	endTime, err := time.Parse(time.RFC3339, endTimeStr)
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("invalid end_time format: %w", err)
	}

	data, err := s.mcpService.FetchTracesOrLogs(ctx, dataType, startTime, endTime, serviceName, limit)
	if err != nil {
		return mcp.ToolsCallResponse{}, err
	}

	result, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return mcp.ToolsCallResponse{}, fmt.Errorf("failed to marshal result: %w", err)
	}

	return mcp.ToolsCallResponse{
		Content: []mcp.Content{
			{
				Type: string(mcp.ContentTypeText),
				Text: string(result),
			},
		},
	}, nil
}

// registerTools registers all available tools
func (s *Server) registerTools() {
	tools := []mcp.Tool{
		{
			Name:        "signoz_test_connection",
			Description: "Verify connectivity to your Signoz instance and configuration",
			InputSchema: mcp.ToolInputSchema{
				Type:       "object",
				Properties: map[string]mcp.Property{},
				Required:   []string{},
			},
		},
		{
			Name:        "signoz_fetch_dashboards",
			Description: "List all available dashboards from Signoz",
			InputSchema: mcp.ToolInputSchema{
				Type:       "object",
				Properties: map[string]mcp.Property{},
				Required:   []string{},
			},
		},
		{
			Name:        "signoz_fetch_dashboard_details",
			Description: "Retrieve detailed information about a specific dashboard by its ID",
			InputSchema: mcp.ToolInputSchema{
				Type: "object",
				Properties: map[string]mcp.Property{
					"dashboard_id": {
						Type:        "string",
						Description: "The ID of the dashboard to fetch details for",
					},
				},
				Required: []string{"dashboard_id"},
			},
		},
		{
			Name:        "signoz_fetch_dashboard_data",
			Description: "Fetch all panel data for a given dashboard by name and time range",
			InputSchema: mcp.ToolInputSchema{
				Type: "object",
				Properties: map[string]mcp.Property{
					"dashboard_name": {
						Type:        "string",
						Description: "The name of the dashboard to fetch data for",
					},
					"start_time": {
						Type:        "string",
						Description: "Start time in RFC3339 format (e.g., 2023-01-01T00:00:00Z)",
						Format:      "date-time",
					},
					"end_time": {
						Type:        "string",
						Description: "End time in RFC3339 format (e.g., 2023-01-01T01:00:00Z)",
						Format:      "date-time",
					},
				},
				Required: []string{"dashboard_name", "start_time", "end_time"},
			},
		},
		{
			Name:        "signoz_fetch_apm_metrics",
			Description: "Retrieve standard APM metrics (request rate, error rate, latency, apdex) for a given service and time range",
			InputSchema: mcp.ToolInputSchema{
				Type: "object",
				Properties: map[string]mcp.Property{
					"service_name": {
						Type:        "string",
						Description: "The name of the service to fetch metrics for",
					},
					"start_time": {
						Type:        "string",
						Description: "Start time in RFC3339 format",
						Format:      "date-time",
					},
					"end_time": {
						Type:        "string",
						Description: "End time in RFC3339 format",
						Format:      "date-time",
					},
				},
				Required: []string{"service_name", "start_time", "end_time"},
			},
		},
		{
			Name:        "signoz_fetch_services",
			Description: "Fetch all instrumented services from Signoz with optional time range filtering",
			InputSchema: mcp.ToolInputSchema{
				Type: "object",
				Properties: map[string]mcp.Property{
					"start_time": {
						Type:        "string",
						Description: "Optional start time in RFC3339 format for filtering",
						Format:      "date-time",
					},
					"end_time": {
						Type:        "string",
						Description: "Optional end time in RFC3339 format for filtering",
						Format:      "date-time",
					},
				},
				Required: []string{},
			},
		},
		{
			Name:        "signoz_execute_clickhouse_query",
			Description: "Execute custom Clickhouse SQL queries via the Signoz API with time range support",
			InputSchema: mcp.ToolInputSchema{
				Type: "object",
				Properties: map[string]mcp.Property{
					"sql": {
						Type:        "string",
						Description: "The SQL query to execute",
					},
					"start_time": {
						Type:        "string",
						Description: "Start time in RFC3339 format",
						Format:      "date-time",
					},
					"end_time": {
						Type:        "string",
						Description: "End time in RFC3339 format",
						Format:      "date-time",
					},
					"params": {
						Type:        "object",
						Description: "Optional query parameters",
					},
				},
				Required: []string{"sql", "start_time", "end_time"},
			},
		},
		{
			Name:        "signoz_execute_builder_query",
			Description: "Execute Signoz builder queries for custom metrics and aggregations with time range support",
			InputSchema: mcp.ToolInputSchema{
				Type: "object",
				Properties: map[string]mcp.Property{
					"query_type": {
						Type:        "string",
						Description: "The type of query (e.g., 'metrics', 'traces')",
					},
					"metric_name": {
						Type:        "string",
						Description: "The name of the metric to query",
					},
					"aggregation": {
						Type:        "string",
						Description: "The aggregation function (e.g., 'sum', 'avg', 'max')",
					},
					"start_time": {
						Type:        "string",
						Description: "Start time in RFC3339 format",
						Format:      "date-time",
					},
					"end_time": {
						Type:        "string",
						Description: "End time in RFC3339 format",
						Format:      "date-time",
					},
					"filters": {
						Type:        "array",
						Description: "Optional filters for the query",
						Items: &mcp.Property{
							Type: "object",
							// Properties for QueryFilter objects would go here if needed
						},
					},
					"group_by": {
						Type:        "array",
						Description: "Optional fields to group by",
						Items: &mcp.Property{
							Type: "string",
						},
					},
					"step": {
						Type:        "string",
						Description: "Optional step duration (e.g., '1m', '5m')",
					},
					"options": {
						Type:        "object",
						Description: "Optional query options",
					},
				},
				Required: []string{"query_type", "metric_name", "aggregation", "start_time", "end_time"},
			},
		},
		{
			Name:        "signoz_fetch_traces_or_logs",
			Description: "Fetch traces or logs from SigNoz using ClickHouse SQL. Specify data_type ('traces' or 'logs'), time range, service name, and limit",
			InputSchema: mcp.ToolInputSchema{
				Type: "object",
				Properties: map[string]mcp.Property{
					"data_type": {
						Type:        "string",
						Description: "The type of data to fetch ('traces' or 'logs')",
						Enum:        []string{"traces", "logs"},
					},
					"service_name": {
						Type:        "string",
						Description: "The name of the service to fetch data for",
					},
					"start_time": {
						Type:        "string",
						Description: "Start time in RFC3339 format",
						Format:      "date-time",
					},
					"end_time": {
						Type:        "string",
						Description: "End time in RFC3339 format",
						Format:      "date-time",
					},
					"limit": {
						Type:        "number",
						Description: "Maximum number of records to return (1-10000)",
						Minimum:     func() *float64 { v := 1.0; return &v }(),
						Maximum:     func() *float64 { v := 10000.0; return &v }(),
					},
				},
				Required: []string{"data_type", "service_name", "start_time", "end_time", "limit"},
			},
		},
	}

	for _, tool := range tools {
		s.tools[tool.Name] = tool
	}

	s.logger.Info("registered MCP tools",
		domain.Field{Key: "tool_count", Value: len(s.tools)},
	)
}

// nextRequestID generates a unique request ID
func (s *Server) nextRequestID() int64 {
	return atomic.AddInt64(&s.requestID, 1)
}
