package mcp

import (
	"context"

	"github.com/google/uuid"
	mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp"

	"github.com/yan1h/agent-coding-workflow/internal/infra/errs"
)

// OrchestratorBridge 是 mcp 调用 orchestrator 服务的窄桥接接口（orchestrator →
// mcp 的既有依赖边由 orchestrator 实现该接口，mcp 不反向 import orchestrator，避免循环）。
type OrchestratorBridge interface {
	// RequestSubtask 让运行中的 agent 为其当前编排 step 派生一个子 step。
	// parentACPSessionID 是调用方所在的 acp session（从 AuthSession 解析）；
	// 返回新建子 step 的 id。
	RequestSubtask(ctx context.Context, parentACPSessionID uuid.UUID, phase string, prompt string, agentKindID *uuid.UUID) (subtaskID string, err error)
}

// registerOrchestratorTools 注册编排器相关 MCP 工具。
func registerOrchestratorTools(srv *mcpsdk.Server, deps ServerDeps) {
	registerRequestSubtask(srv, deps)
}

// ===== request_subtask =====

type requestSubtaskIn struct {
	Phase       string `json:"phase,omitempty" jsonschema:"target phase for the subtask (defaults to the parent step phase)"`
	Prompt      string `json:"prompt" jsonschema:"prompt for the child agent"`
	AgentKindID string `json:"agent_kind_id,omitempty" jsonschema:"optional agent kind UUID for the subtask"`
}

type requestSubtaskOut struct {
	OK     bool   `json:"ok"`
	StepID string `json:"step_id"`
}

func registerRequestSubtask(srv *mcpsdk.Server, deps ServerDeps) {
	mcpsdk.AddTool(srv,
		&mcpsdk.Tool{
			Name:        "request_subtask",
			Description: "Ask the orchestrator to spawn a child step (sub-agent) for the current run, subject to depth and fan-out limits. Only callable from within an active agent session.",
		},
		func(ctx context.Context, _ *mcpsdk.CallToolRequest, in requestSubtaskIn) (*mcpsdk.CallToolResult, requestSubtaskOut, error) {
			if err := CheckToolFromCtx(ctx, "request_subtask"); err != nil {
				return nil, requestSubtaskOut{}, err
			}
			if deps.Orchestrator == nil {
				return nil, requestSubtaskOut{}, errs.New(errs.CodeNotFound, "orchestrator not enabled")
			}
			// request_subtask 是 create_acp_session 的逆向闸门：只有在 session 内的
			// agent（system token）可调，普通用户/admin token 不可（它们走 StartRun）。
			sess, ok := FromContext(ctx)
			if !ok {
				return nil, requestSubtaskOut{}, errs.New(errs.CodeInternal, "mcp: AuthSession missing")
			}
			if sess.Issuer != IssuerSystem {
				return nil, requestSubtaskOut{}, errs.New(errs.CodeForbidden,
					"request_subtask is only callable from within an agent session")
			}
			if sess.ACPSessionID == nil || *sess.ACPSessionID == uuid.Nil {
				return nil, requestSubtaskOut{}, errs.New(errs.CodeForbidden,
					"calling token is not bound to an acp session")
			}
			if in.Prompt == "" {
				return nil, requestSubtaskOut{}, errs.New(errs.CodeInvalidInput, "prompt is required")
			}

			var akID *uuid.UUID
			if in.AgentKindID != "" {
				id, perr := uuid.Parse(in.AgentKindID)
				if perr != nil {
					return nil, requestSubtaskOut{}, errs.Wrap(perr, errs.CodeInvalidInput, "agent_kind_id parse")
				}
				akID = &id
			}

			stepID, err := deps.Orchestrator.RequestSubtask(ctx, *sess.ACPSessionID, in.Phase, in.Prompt, akID)
			if err != nil {
				return nil, requestSubtaskOut{}, err
			}
			return nil, requestSubtaskOut{OK: true, StepID: stepID}, nil
		})
}
