// gate.go 实现阶段网关：把"agent 停了"（stopReason）与"工作确实就绪"（产物/issue
// 谓词）结合，避免仅凭 end_turn 就静默把需求标记完成。v1 是可插拔的 per-phase 谓词。
package orchestrator

import (
	"context"

	"github.com/google/uuid"

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

// GateArtifactAccess 是网关查询某需求阶段产物的窄接口（app 层用 project.ArtifactService 适配）。
type GateArtifactAccess interface {
	// ListArtifacts 返回某 requirement 在某 phase 的产物（phase 传零值 "" 表示全部阶段）。
	ListArtifacts(ctx context.Context, projectID, requirementID uuid.UUID, phase project.Phase) ([]*project.Artifact, error)
}

// GateIssueAccess 是网关查询某需求未关闭 issue 数的窄接口（app 层用 project.IssueService/Repository 适配）。
type GateIssueAccess interface {
	CountOpenIssues(ctx context.Context, requirementID uuid.UUID) (int, error)
}

// v1Gate 是 v1 阶段网关：
//
//   - stopReason 必须是 end_turn，否则不通过。refusal/max_tokens 等明确是 agent
//     主动放弃/受限，不通过且不重试（Retry=false → dead-letter）。其它非空 stopReason
//     不通过但可重试。
//   - 产物型阶段（planning/prototyping/auditing/implementing/reviewing）额外要求该阶段
//     已有至少一个产物；缺失则不通过但可重试（让 agent 再跑一次产出）。
//   - reviewing/done 额外检查未关闭 issue 数为 0（有开放 issue 视为未就绪，可重试）。
//   - done 阶段：end_turn 即视为通过（汇总视图，无单独产物）。
type v1Gate struct {
	artifacts GateArtifactAccess // 可为 nil（跳过产物谓词）
	issues    GateIssueAccess    // 可为 nil（跳过 issue 谓词）
}

// NewV1Gate 构造 v1 阶段网关。artifacts/issues 可为 nil（对应谓词被跳过）。
func NewV1Gate(artifacts GateArtifactAccess, issues GateIssueAccess) PhaseGate {
	return &v1Gate{artifacts: artifacts, issues: issues}
}

func (g *v1Gate) Evaluate(ctx context.Context, run *Run, step *Step, stopReason string) (GateResult, error) {
	// 1. stopReason 闸门。
	switch stopReason {
	case string(acpStopEndTurn):
		// 继续 phase 谓词。
	case string(acpStopRefusal), string(acpStopMaxTokens):
		return GateResult{Pass: false, Retry: false,
			Reason: "agent stopped with non-recoverable reason: " + stopReason}, nil
	default:
		// 空串 / cancelled / vendor-specific：不通过，可重试。
		reason := stopReason
		if reason == "" {
			reason = "no stop reason"
		}
		return GateResult{Pass: false, Retry: true,
			Reason: "turn did not end cleanly: " + reason}, nil
	}

	phase := step.Phase

	// 2. done：end_turn 即通过。
	if phase == project.PhaseDone {
		return GateResult{Pass: true, Reason: "done"}, nil
	}

	// 3. 产物型阶段：要求该阶段已有产物。
	if phase.IsArtifactPhase() && g.artifacts != nil {
		arts, err := g.artifacts.ListArtifacts(ctx, run.ProjectID, run.RequirementID, phase)
		if err != nil {
			return GateResult{}, err
		}
		if len(arts) == 0 {
			return GateResult{Pass: false, Retry: true,
				Reason: "no artifact produced for phase " + string(phase),
				Detail: map[string]any{"phase": string(phase)}}, nil
		}
	}

	// 4. reviewing：额外要求无开放 issue（避免遗留缺陷推进）。
	if phase == project.PhaseReviewing && g.issues != nil {
		open, err := g.issues.CountOpenIssues(ctx, run.RequirementID)
		if err != nil {
			return GateResult{}, err
		}
		if open > 0 {
			return GateResult{Pass: false, Retry: true,
				Reason: "open issues remain",
				Detail: map[string]any{"open_issues": open}}, nil
		}
	}

	return GateResult{Pass: true, Reason: "phase gate passed",
		Detail: map[string]any{"phase": string(phase)}}, nil
}

// acp stopReason 原始字符串常量（与 internal/acp.StopReason 取值一致，此处复制以免引入
// acp 依赖到纯网关逻辑）。
const (
	acpStopEndTurn   = "end_turn"
	acpStopRefusal   = "refusal"
	acpStopMaxTokens = "max_tokens"
)
