package mcp

import (
	"context"
	"testing"

	"github.com/google/uuid"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// fakeOrchBridge implements OrchestratorBridge.
type fakeOrchBridge struct {
	lastParent uuid.UUID
	lastPhase  string
	lastPrompt string
	stepID     string
	err        error
}

func (f *fakeOrchBridge) RequestSubtask(_ context.Context, parentACPSessionID uuid.UUID, phase, prompt string, _ *uuid.UUID) (string, error) {
	if f.err != nil {
		return "", f.err
	}
	f.lastParent = parentACPSessionID
	f.lastPhase = phase
	f.lastPrompt = prompt
	if f.stepID == "" {
		f.stepID = uuid.NewString()
	}
	return f.stepID, nil
}

func orchTestDeps() (ServerDeps, *fakeOrchBridge) {
	deps := testDeps()
	bridge := &fakeOrchBridge{}
	deps.Orchestrator = bridge
	return deps, bridge
}

// ctxWithSystemToken 构造一个 system token 上下文（绑定 acp session）。
func ctxWithSystemToken(sessionID uuid.UUID) context.Context {
	return context.WithValue(context.Background(), AuthContextKey, &AuthSession{
		UserID:       testUID.String(),
		TokenID:      uuid.NewString(),
		Issuer:       IssuerSystem,
		ACPSessionID: &sessionID,
	})
}

func TestRequestSubtask_SystemTokenHappyPath(t *testing.T) {
	deps, bridge := orchTestDeps()
	sessionID := uuid.New()

	result, err := callTool(ctxWithSystemToken(sessionID), deps, "request_subtask", map[string]any{
		"phase":  "implementing",
		"prompt": "do the subtask",
	})
	require.NoError(t, err)
	require.False(t, result.IsError, "expected success; got %+v", result)
	assert.Equal(t, sessionID, bridge.lastParent)
	assert.Equal(t, "implementing", bridge.lastPhase)
	assert.Equal(t, "do the subtask", bridge.lastPrompt)
}

func TestRequestSubtask_RejectsAdminToken(t *testing.T) {
	deps, bridge := orchTestDeps()

	// admin token（非 system）→ 拒绝（request_subtask 只允许 in-session agent）。
	ctx := context.WithValue(context.Background(), AuthContextKey, &AuthSession{
		UserID:  testUID.String(),
		TokenID: uuid.NewString(),
		Issuer:  IssuerAdmin,
	})
	result, err := callTool(ctx, deps, "request_subtask", map[string]any{
		"phase":  "implementing",
		"prompt": "x",
	})
	require.NoError(t, err)
	assert.True(t, result.IsError, "admin token must be rejected")
	assert.Empty(t, bridge.lastPrompt)
}

func TestRequestSubtask_RejectsSystemTokenWithoutSession(t *testing.T) {
	deps, _ := orchTestDeps()

	// system token 但未绑定 acp session → 拒绝。
	ctx := context.WithValue(context.Background(), AuthContextKey, &AuthSession{
		UserID:  testUID.String(),
		TokenID: uuid.NewString(),
		Issuer:  IssuerSystem,
	})
	result, err := callTool(ctx, deps, "request_subtask", map[string]any{
		"phase":  "implementing",
		"prompt": "x",
	})
	require.NoError(t, err)
	assert.True(t, result.IsError, "system token without acp session must be rejected")
}

func TestRequestSubtask_RequiresPrompt(t *testing.T) {
	deps, _ := orchTestDeps()
	result, err := callTool(ctxWithSystemToken(uuid.New()), deps, "request_subtask", map[string]any{
		"phase": "implementing",
	})
	require.NoError(t, err)
	assert.True(t, result.IsError, "missing prompt must error")
}
