package mcp

import (
	
	
	

	
	
	amhelp 

	am 
)

type Opts struct {
	StatesInclude  am.S
	StatesExclude  am.S
	StatesReadonly am.S
	// list of typed args
	Args []am.ArgsApi
	// RPC args parser
	ArgsUnmarshaller amhelp.ArgsUnmarshallerFn
	CallSignatures   []am.CallSignature
	// optional func to call after a mutation
	MutCallback func(ctx context.Context) error
	Version     string
	Name        string
	Desc        string
	StateCalls  []am.CallSignature
}

type Server struct {
	Mach am.Api
	Mcp  *server.MCPServer
	Http *server.StreamableHTTPServer
	Opts Opts

	// all the names of type safe args
	argNames []string
}

func ( am.Api,  Opts) (*Server, error) {
	var  error

	// validate
	if .Args == nil {
		return nil, fmt.Errorf("field ArgsBase required")
	}
	if .Name == "" {
		return nil, fmt.Errorf("field Name required")
	}
	if .Version == "" {
		return nil, fmt.Errorf("field Version required")
	}
	if .ArgsUnmarshaller == nil {
		.ArgsUnmarshaller = amhelp.NewArgsUnmarshaller(.Args)
	}

	// Create a new MCP server
	 := server.NewMCPServer(.Name, .Version,
		server.WithToolCapabilities(false),
		server.WithDescription(.Desc),
	)

	 := &Server{
		Mach: ,
		Mcp:  ,
		Opts: ,
	}

	// MACHINE

	// collect arg names
	.argNames,  = amhelp.ArgsNames(.Args)
	if  != nil {
		return nil, 
	}
	var  []mcp.ToolOption
	for ,  := range .argNames {
		 = append(, mcp.WithString())
	}

	// Add
	 := []mcp.ToolOption{
		mcp.WithDescription("Add a state with optional params"),
		mcp.WithString("state",
			mcp.Required(),
			mcp.Description("Name of the state to add"),
			mcp.Enum(.StateNames()...),
		),
	}
	 = append(, ...)
	 := mcp.NewTool("Add", ...)

	// Remove
	 = []mcp.ToolOption{
		mcp.WithDescription("Remove a state with optional params"),
		mcp.WithString("state",
			mcp.Required(),
			mcp.Description("Name of the state to remove"),
			// TODO allowlist
			mcp.Enum(.StateNames()...),
		),
	}
	 = append(, ...)
	 := mcp.NewTool("Remove", ...)

	// specified call signatures
:
	for ,  := range .StateCalls {
		// perms
		for ,  := range .States {
			if !.stateMutable() {
				continue 
			}
		}

		,  := .newCallSigHandler(&)
		.AddTool(, )
	}

	// TODO Serialize, Inspect, Times (sum, queueTick, machTick)

	// bind handlers
	.AddTool(, .mutAdd)
	.AddTool(, .mutRemove)

	.Http = server.NewStreamableHTTPServer()

	return , nil
}

func ( *Server) (
	 context.Context,  mcp.CallToolRequest,
) (*mcp.CallToolResult, error) {
	,  := .RequireString("state")
	if  != nil {
		return mcp.NewToolResultError(.Error()), nil
	}

	// perms
	if !.stateMutable() {
		return mcp.NewToolResultError(fmt.Sprintf(
			"state %s not allowed", )), nil
	}

	// parse args
	 := am.A{"FromMCP": true}
	for ,  := range .argNames {
		if  := .GetString(, "");  != "" {
			[] = 
		}
	}

	// mutate
	 := .Mach.Add1(, .Opts.ArgsUnmarshaller())

	// wait until processed
	if  == am.Canceled {
		return mcp.NewToolResultError("canceled"), nil
	}
	select {
	case <-.Mach.WhenQueue():
	case <-.Done():
		return nil, .Err()
	}

	// callback
	if .Opts.MutCallback != nil {
		 := .Opts.MutCallback()
		if  != nil {
			return mcp.NewToolResultError(fmt.Sprintf(
				"callback error: %s", )), nil
		}
	}

	return .response()
}

func ( *Server) (
	 context.Context,  mcp.CallToolRequest,
) (*mcp.CallToolResult, error) {
	,  := .RequireString("state")
	if  != nil {
		return mcp.NewToolResultError(.Error()), nil
	}

	// perms
	if !.stateMutable() {
		return mcp.NewToolResultError(fmt.Sprintf(
			"state %s not allowed", )), nil
	}

	// parse args
	 := am.A{"FromMCP": true}
	for ,  := range .argNames {
		[] = .GetString(, "")
	}

	// mutate
	 := .Mach.Add1(, nil)

	// wait until processed
	if  == am.Canceled {
		return mcp.NewToolResultError("canceled"), nil
	}
	select {
	case <-.Mach.WhenQueue():
	case <-.Done():
		return nil, .Err()
	}

	// callback
	if .Opts.MutCallback != nil {
		 := .Opts.MutCallback()
		if  != nil {
			return mcp.NewToolResultError(fmt.Sprintf(
				"callback error: %s", )), nil
		}
	}

	return .response()
}

func ( *Server) (
	 *am.CallSignature,
) (mcp.Tool, server.ToolHandlerFunc) {
	 := .Name
	if  == "" {
		 = .String()
	}

	// collect opts
	var  []mcp.ToolOption
	if .Desc != "" {
		 = append(, mcp.WithDescription(.Desc))
	}

	// collect args
	for ,  := range .Args() {
		var  []mcp.PropertyOption
		if ,  := .Values[];  {
			 = append(, mcp.Enum(...))
		}
		if slices.Contains(.Needed, ) {
			 = append(, mcp.Required())
		}
		 = append(, mcp.WithString(, ...))
	}

	// tool & handler
	 := mcp.NewTool(, ...)
	return , func(
		 context.Context,  mcp.CallToolRequest,
	) (*mcp.CallToolResult, error) {
		// parse args
		 := am.A{"FromMCP": true}
		for ,  := range .Args() {
			[] = .GetString(, "")
		}

		// mutate
		var  am.Result
		if .IsRemove {
			 = .Mach.Remove(.States, .Opts.ArgsUnmarshaller())
		} else {
			 = .Mach.Add(.States, .Opts.ArgsUnmarshaller())
		}

		// wait until processed
		if  == am.Canceled {
			return mcp.NewToolResultError("canceled"), nil
		}
		select {
		case <-.Mach.WhenQueue():
		case <-.Done():
			return nil, .Err()
		}

		// callback
		if .Opts.MutCallback != nil {
			 := .Opts.MutCallback()
			if  != nil {
				return mcp.NewToolResultError(fmt.Sprintf(
					"callback error: %s", )), nil
			}
		}

		return .response()
	}
}

// response is a generic response with clocks of active states
func ( *Server) () (*mcp.CallToolResult, error) {
	 := "("
	for ,  := range .Mach.Clock(nil) {
		if !.stateMutable() &&
			!slices.Contains(.Opts.StatesReadonly, ) {

			continue
		}
		if !am.IsActiveTick() {
			continue
		}
		if  != "(" {
			 += " "
		}
		 += fmt.Sprintf("%s:%d", , )
	}

	return mcp.NewToolResultText( + ")"), nil
}

func ( *Server) ( string) bool {
	if len(.Opts.StatesInclude) > 0 {
		return slices.Contains(.Opts.StatesInclude, )
	}

	return !slices.Contains(.Opts.StatesExclude, )
}

func ( *Server) () am.S {
	return slices.DeleteFunc(slices.Clone(.Mach.StateNames()),
		func( string) bool {
			return !.stateMutable()
		})
}