// planner.go 是纯函数（无 I/O）的阶段规划逻辑：阶段→agent-kind 解析、阶段→prompt
// 组装、网关结果→下一阶段。可独立单测（模仿 acp.ResolveBranch 的取舍）。
package orchestrator

import (
	"fmt"
	"strings"

	"github.com/google/uuid"

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

// phaseOrder 是 6 阶段的线性推进顺序，对应 project.AllPhases。
var phaseOrder = project.AllPhases

// NextPhase 根据当前阶段与网关结果决定下一阶段。
//
//   - 网关未通过（!g.Pass）→ 回环本阶段（next==current，terminal=false），让 step
//     在同阶段重试。
//   - 网关通过且 current==done → 终态（terminal=true），run 成功。
//   - 网关通过且 current!=done → 线性推进到下一阶段。
//
// current 非法（不在枚举内）时视为终态，避免无限循环。
func NextPhase(current project.Phase, g GateResult) (next project.Phase, terminal bool) {
	if !g.Pass {
		return current, false
	}
	if current == project.PhaseDone {
		return project.PhaseDone, true
	}
	for i, p := range phaseOrder {
		if p == current {
			if i+1 >= len(phaseOrder) {
				// current 已是最后一个阶段（done）——由上面的分支处理；兜底终止。
				return project.PhaseDone, true
			}
			// 推进到下一阶段。即便下一阶段是 done，也非终态：done 仍要跑一个 step，
			// 只有 done 阶段网关通过后（current==done 分支）run 才成功。
			return phaseOrder[i+1], false
		}
	}
	// 未知阶段：保守终止。
	return current, true
}

// PhaseAgentKind 解析某阶段应使用的 agent-kind：优先 run.config 覆盖，否则退回
// defaults（app 层从配置注入的"阶段→默认 agent-kind"映射）。两者皆缺则报错。
func PhaseAgentKind(cfg RunConfig, phase project.Phase, defaults map[project.Phase]uuid.UUID) (uuid.UUID, error) {
	if cfg.PhaseAgentKinds != nil {
		if id, ok := cfg.PhaseAgentKinds[phase]; ok && id != uuid.Nil {
			return id, nil
		}
	}
	if defaults != nil {
		if id, ok := defaults[phase]; ok && id != uuid.Nil {
			return id, nil
		}
	}
	return uuid.Nil, errs.New(errs.CodeInvalidInput,
		fmt.Sprintf("no agent kind configured for phase %q", phase))
}

// BuildPrompt 组装某阶段发给 agent 的 prompt。config 提供覆盖模板时优先用覆盖
// （仍前置需求/产物上下文）；否则用内置的 per-phase 默认指令。纯字符串拼接，无 I/O。
func BuildPrompt(phase project.Phase, req *project.Requirement, artifacts []*project.Artifact, override string) string {
	var b strings.Builder

	if req != nil {
		fmt.Fprintf(&b, "Requirement #%d: %s\n", req.Number, req.Title)
		if strings.TrimSpace(req.Description) != "" {
			fmt.Fprintf(&b, "\nDescription:\n%s\n", strings.TrimSpace(req.Description))
		}
	}

	if len(artifacts) > 0 {
		b.WriteString("\nPrior artifacts:\n")
		for _, a := range artifacts {
			if a == nil {
				continue
			}
			fmt.Fprintf(&b, "- [%s v%d] %s\n", a.Phase, a.Version, summarizeArtifact(a))
		}
	}

	b.WriteString("\nCurrent phase: ")
	b.WriteString(string(phase))
	b.WriteString("\n\n")

	if strings.TrimSpace(override) != "" {
		b.WriteString(strings.TrimSpace(override))
		b.WriteString("\n")
		return b.String()
	}

	b.WriteString(defaultPhaseInstruction(phase))
	b.WriteString("\n")
	return b.String()
}

// summarizeArtifact 取产物内容首行（截断）作为简介，避免 prompt 过长。
func summarizeArtifact(a *project.Artifact) string {
	content := strings.TrimSpace(a.Content)
	if content == "" {
		return "(empty)"
	}
	if idx := strings.IndexByte(content, '\n'); idx >= 0 {
		content = content[:idx]
	}
	if len(content) > 120 {
		content = content[:120] + "..."
	}
	return content
}

// defaultPhaseInstruction 是每个阶段的内置默认指令。
func defaultPhaseInstruction(phase project.Phase) string {
	switch phase {
	case project.PhasePlanning:
		return "Produce a clear plan for this requirement and record it as a planning artifact."
	case project.PhasePrototyping:
		return "Build a prototype validating the approach and record a prototyping artifact."
	case project.PhaseAuditing:
		return "Audit the plan/prototype for risks and gaps; record an auditing artifact."
	case project.PhaseImplementing:
		return "Implement the requirement on this worktree; commit your changes."
	case project.PhaseReviewing:
		return "Review the implementation, fix issues, and record a reviewing artifact."
	case project.PhaseDone:
		return "Summarize the completed work; no further action is required."
	default:
		return "Proceed with the current phase."
	}
}
