package mcp

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/AgentTeam/desktop/internal/types"
)

// RegisterDiscoveryRoutes installs MCP OAuth/OpenID discovery endpoints.
func RegisterDiscoveryRoutes(r gin.IRoutes) {
	unsupportedOAuth := func(c *gin.Context) {
		writeWellKnownUnsupported(c, "oauth-authorization-server")
	}
	unsupportedOpenID := func(c *gin.Context) {
		writeWellKnownUnsupported(c, "openid-configuration")
	}

	r.GET(oauthAuthorizationServerPath, unsupportedOAuth)
	r.GET(oauthAuthorizationServerPath+"/*resourcePath", unsupportedOAuth)
	r.GET(openIDConfigurationPath, unsupportedOpenID)
	r.GET(openIDConfigurationPath+"/*resourcePath", unsupportedOpenID)
	r.GET(oauthProtectedResourcePath, func(c *gin.Context) {
		writeProtectedResourceMetadata(c, "")
	})
	r.GET(oauthProtectedResourcePath+"/*resourcePath", func(c *gin.Context) {
		writeProtectedResourceMetadata(c, protectedResourceBasePathFromWildcard(c))
	})

	r.GET("/mcp/server/:serverId/:agentId"+oauthAuthorizationServerPath, unsupportedOAuth)
	r.GET("/mcp/server/:serverId/:agentId"+openIDConfigurationPath, unsupportedOpenID)
	r.GET("/mcp/server/:serverId/:agentId"+oauthProtectedResourcePath, func(c *gin.Context) {
		writeProtectedResourceMetadata(c, protectedResourceBasePathFromSuffix(c))
	})
	r.GET("/api/internal/mcp/servers/:serverId/agents/:agentId"+oauthAuthorizationServerPath, unsupportedOAuth)
	r.GET("/api/internal/mcp/servers/:serverId/agents/:agentId"+openIDConfigurationPath, unsupportedOpenID)
	r.GET("/api/internal/mcp/servers/:serverId/agents/:agentId"+oauthProtectedResourcePath, func(c *gin.Context) {
		writeProtectedResourceMetadata(c, protectedResourceBasePathFromSuffix(c))
	})
	r.GET("/mcp/agentteam/:serverId/:agentId"+oauthAuthorizationServerPath, unsupportedOAuth)
	r.GET("/mcp/agentteam/:serverId/:agentId"+openIDConfigurationPath, unsupportedOpenID)
	r.GET("/mcp/agentteam/:serverId/:agentId"+oauthProtectedResourcePath, func(c *gin.Context) {
		writeProtectedResourceMetadata(c, protectedResourceBasePathFromSuffix(c))
	})
}

// ---------------------------------------------------------------------------
// StreamHandler — GET (SSE stream or JSON info)
// ---------------------------------------------------------------------------

// newStreamHandler returns a gin handler for SSE streaming or JSON server info.
type handlerResolver func(key string) (types.MCPHandler, bool)

// handlerContextResolver resolves a route key to its MCP handler with access to
// authenticated request context.
type handlerContextResolver func(c *gin.Context, key string) (types.MCPHandler, bool)

// RegisterHandlerRoutes registers MCP routes at /:serverId/:agentId.
// The server connection is resolved at request time from the resolver
// function, supporting multiple AgentTeam server connections.
func RegisterHandlerRoutes(group *gin.RouterGroup, resolve handlerResolver) {
	RegisterParamHandlerRoutes(group, "serverId", resolve)
}

// RegisterParamHandlerRoutes registers MCP routes and resolves a named path parameter to an
// MCP handler. This supports MCP endpoints whose first variable is not a
// server ID.
func RegisterParamHandlerRoutes(group *gin.RouterGroup, paramName string, resolve handlerResolver) {
	RegisterContextHandlerRoutes(group, paramName, func(_ *gin.Context, key string) (types.MCPHandler, bool) {
		return resolve(key)
	})
}

// RegisterContextHandlerRoutes registers MCP routes using a named route parameter
// and request-aware handler resolver.
func RegisterContextHandlerRoutes(group *gin.RouterGroup, paramName string, resolve handlerContextResolver) {
	group.GET("", newStreamHandler())
	group.POST("", func(c *gin.Context) {
		key := c.Param(paramName)
		handler, ok := resolve(c, key)
		if !ok {
			c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
				"error": "mcp endpoint not found: " + key,
			})
			return
		}
		dispatchRPCBatch(c, handler)
	})
	group.DELETE("", newDisconnectHandler())
}
