package wire

import (
	"context"
	"strings"
	"sync"
)

// agentLifecycleTaskOwner is one receipt-ordered per-agent lifecycle command.
// The predecessor chain, rather than goroutine mutex acquisition order, makes
// Session Link frame order authoritative even when handlers run asynchronously.
type agentLifecycleTaskOwner struct {
	done     chan struct{}
	doneOnce sync.Once
}

func (c *Protocol) startAgentLifecycleTask(
	ctx context.Context,
	agentID string,
	task func(context.Context),
) bool {
	if c == nil || task == nil {
		return false
	}
	agentID = strings.TrimSpace(agentID)
	if agentID == "" {
		return c.startConnectionRunTask(ctx, task)
	}

	owner := &agentLifecycleTaskOwner{done: make(chan struct{})}
	c.mu.Lock()
	if c.agents == nil {
		c.agents = make(map[string]*agentState)
	}
	state := c.getOrCreateAgentState(agentID)
	predecessor := state.lifecycleTail
	state.lifecycleTail = owner
	c.mu.Unlock()

	started := c.startConnectionRunTask(ctx, func(taskCtx context.Context) {
		defer c.finishAgentLifecycleTask(agentID, owner)
		if predecessor != nil {
			select {
			case <-predecessor.done:
			case <-taskCtx.Done():
				return
			}
		}
		if err := taskCtx.Err(); err != nil {
			return
		}
		task(taskCtx)
	})
	if !started {
		c.finishAgentLifecycleTask(agentID, owner)
	}
	return started
}

func (c *Protocol) finishAgentLifecycleTask(agentID string, owner *agentLifecycleTaskOwner) {
	if c == nil || owner == nil {
		return
	}
	owner.doneOnce.Do(func() { close(owner.done) })
	c.mu.Lock()
	if state, ok := c.agents[agentID]; ok && state != nil && state.lifecycleTail == owner {
		state.lifecycleTail = nil
	}
	c.mu.Unlock()
}
