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)
	addr := fmt.Sprintf("127.0.0.1:%d", flag.Port)

	switch flag.Mode {
	case "stdio":
		if err := server.ServeStdio(mcpServer); err != nil {
			return err
		}
	case "sse":
		sseServer := server.NewSSEServer(mcpServer)
		log.Infof("Gitea MCP Server running:")
		log.Infof("        sse: http://%s/", addr)
		if err := sseServer.Start(fmt.Sprintf(":%d", flag.Port)); err != nil {
			return err
		}
	case "http":
		httpServer := server.NewStreamableHTTPServer(mcpServer)
		log.Infof("Gitea MCP Server running:")
		log.Infof("        http: http://%s/", addr)
		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
		log.Infof("Network mode: Creating streamable HTTP server...")
		streamableServer := server.NewStreamableHTTPServer(mcpServer)
		log.Infof("Network mode: Created streamable HTTP server")

		log.Infof("Network mode: Creating SSE server...")
		sseServer := server.NewSSEServer(mcpServer,
			server.WithSSEEndpoint("/sse"),
			server.WithMessageEndpoint("/message"),
		)
		log.Infof("Network mode: Created SSE server")

		// Create custom HTTP mux
		log.Infof("Network mode: Creating HTTP mux...")
		mux := http.NewServeMux()
		mux.Handle("/mcp", streamableServer)
		mux.Handle("/", sseServer)
		log.Infof("Network mode: Configured HTTP routes")

		// Start single HTTP server
		log.Infof("Gitea MCP Server running in network mode:")
		log.Infof("        http: http://%s/mcp", addr)
		log.Infof("        sse:  http://%s/sse", addr)
		err := http.ListenAndServe(fmt.Sprintf(":%d", flag.Port), mux)
		log.Errorf("Network mode: ListenAndServe returned with error: %v", err)
		return err
	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(),
	)
}
