package operation

import (
	"fmt"
	"net/http"

	"gitea.com/gitea/gitea-mcp/operation/issue"
	"gitea.com/gitea/gitea-mcp/operation/pull"
	"gitea.com/gitea/gitea-mcp/operation/repo"
	"gitea.com/gitea/gitea-mcp/operation/search"
	"gitea.com/gitea/gitea-mcp/operation/user"
	"gitea.com/gitea/gitea-mcp/operation/version"
	"gitea.com/gitea/gitea-mcp/pkg/flag"
	"gitea.com/gitea/gitea-mcp/pkg/log"

	"github.com/mark3labs/mcp-go/server"
)

var mcpServer *server.MCPServer

func RegisterTool(s *server.MCPServer) {
	// User Tool
	s.AddTools(user.Tool.Tools()...)

	// Repo Tool
	s.AddTools(repo.Tool.Tools()...)

	// Issue Tool
	s.AddTools(issue.Tool.Tools()...)

	// Pull Tool
	s.AddTools(pull.Tool.Tools()...)

	// Search Tool
	s.AddTools(search.Tool.Tools()...)

	// Version Tool
	s.AddTools(version.Tool.Tools()...)

	s.DeleteTools("")
}

func Run() error {
	mcpServer = newMCPServer(flag.Version)
	RegisterTool(mcpServer)
	switch flag.Mode {
	case "stdio":
		if err := server.ServeStdio(mcpServer); err != nil {
			return err
		}
	case "sse":
		sseServer := server.NewSSEServer(mcpServer)
		log.Infof("Gitea MCP SSE server listening on :%d", flag.Port)
		if err := sseServer.Start(fmt.Sprintf(":%d", flag.Port)); err != nil {
			return err
		}
	case "http":
		httpServer := server.NewStreamableHTTPServer(mcpServer)
		log.Infof("Gitea MCP HTTP server listening on :%d", flag.Port)
		if err := httpServer.Start(fmt.Sprintf(":%d", flag.Port)); err != nil {
			return err
		}
	case "network":
		// Network mode: serve both HTTP and SSE on same port with different URLs
		streamableServer := server.NewStreamableHTTPServer(mcpServer)
		sseServer := server.NewSSEServer(mcpServer)
		
		// Create custom HTTP mux
		mux := http.NewServeMux()
		mux.Handle("/mcp", streamableServer)
		mux.Handle("/sse", sseServer)
		
		// Start single HTTP server
		log.Infof("Gitea MCP server listening on :%d (/mcp, /sse)", flag.Port)
		return http.ListenAndServe(fmt.Sprintf(":%d", flag.Port), mux)
	default:
		return fmt.Errorf("invalid transport type: %s. Must be 'stdio', 'sse', 'http' or 'network'", flag.Mode)
	}
	return nil
}

func newMCPServer(version string) *server.MCPServer {
	return server.NewMCPServer(
		"Gitea MCP Server",
		version,
		server.WithToolCapabilities(true),
		server.WithLogging(),
		server.WithRecovery(),
	)
}
