package nats

import (
	
	

	

	
	am 
)

// ExposeMachine exposes a state machine to NATS for requests of type
// - GetterReq
// - MutationReq
// - WaitingReq
// with responses of type
// - GetterResp
// - MutationResp
// - WaitingResp
//
// Each state machine subscribed to a dedicated subtopic "[topic].[machineID]".
// Optional [queue] allows to load-balance requests across multiple subscribers.
// ExposeMachine allocates a goroutine for GC blocked by ctx.
func (
	 context.Context,  am.Api,  *nats.Conn, ,  string,
) error {
	var (
		 *nats.Subscription
		  error
	)

	 := func( *nats.Msg) {
		dispatcher(, , , )
	}

	if  != "" {
		,  = .QueueSubscribe(, , )
	} else {
		,  = .Subscribe(, )
	}

	if  != nil {
		return 
	}

	// dedicated subtopic for this machine
	,  := .Subscribe(+"."+.Id(), )
	if  != nil {
		_ = .Unsubscribe()
		return 
	}

	// dispose with ctx
	go func() {
		<-.Done()
		_ = .Unsubscribe()
		_ = .Unsubscribe()
	}()

	return 
}

// Add is a helper to add a list of states to machine machID, exposed
// under [topic]. It will block until the response or the context expires.
func (
	 context.Context,  *nats.Conn, ,  string,  am.S,
	 am.A) (am.Result, error) {

	// create the request
	 := integrations.NewMutationReq()
	.Add = 
	.Args = 
	,  := json.Marshal()
	if  != nil {
		return am.Canceled, 
	}

	,  := .RequestWithContext(, +"."+, )
	if  != nil {
		return am.Canceled, 
	}

	var  integrations.MutationResp
	 = json.Unmarshal(.Data, &)

	return .Result, 
}

// Remove is a helper to remove a list of states from machine machID,
// exposed under [topic]. It will block until the response or the context
// expires.
func (
	 context.Context,  *nats.Conn, ,  string,  am.S,
	 am.A,
) (am.Result, error) {

	// create the request
	 := integrations.NewMutationReq()
	.Remove = 
	.Args = 
	,  := json.Marshal()
	if  != nil {
		return am.Canceled, 
	}

	,  := .RequestWithContext(, +"."+, )
	if  != nil {
		return am.Canceled, 
	}

	var  integrations.MutationResp
	 = json.Unmarshal(.Data, &)

	return .Result, 
}

// UTILS

func dispatcher(
	 context.Context,  *nats.Conn,  am.Api,  *nats.Msg) {
	var (
		    []byte
		 error
	)

	// check if this is something for us
	 := integrations.MsgKindReq{}
	if  := json.Unmarshal(.Data, &);  != nil ||
		!integrations.KindEnum.Contains(.Kind) {

		// no match, exit
		return
	}

	 := &integrations.GetterReq{}
	 := &integrations.MutationReq{}
	 := &integrations.WaitingReq{}

	switch .Kind {
	case integrations.KindReqGetter:
		if  = json.Unmarshal(.Data, );  == nil {
			,  := integrations.HandlerGetter(, , )
			if  != nil {
				 = 
			} else {
				,  = json.Marshal()
			}
		}

	case integrations.KindReqMutation:
		if  = json.Unmarshal(.Data, );  == nil {
			,  := integrations.HandlerMutation(, , )
			if  != nil {
				 = 
			} else {
				,  = json.Marshal()
			}
		}

	case integrations.KindReqWaiting:
		if  = json.Unmarshal(.Data, );  == nil {
			,  := integrations.HandlerWaiting(, , )
			if  != nil {
				 = 
			} else {
				,  = json.Marshal()
			}
		}
	}

	// internal err
	if  != nil {
		.AddErr(, nil)
		return
	}

	// opt response
	if  != nil {
		// publish for async replies
		if .Kind == integrations.KindReqWaiting {
			 = .Publish(.Subject, )

			// response to sync request
		} else {
			 = .Respond()
		}
		if  != nil {
			.AddErr(, nil)
		}
	}
}