package exec

import "strings"

func typedAllowedOutputPaths(key string, selectors []auditSelector) []auditPath {
	if key == "agent list" {
		return []auditPath{
			outputItem("agents", "id"), outputItem("agents", "name"), outputItem("agents", "runtime"),
			outputItem("agents", "status"), outputItem("agents", "backendRegistered"),
			outputItem("agents", "apiKeyConfigured"), outputItem("agents", "configuredHeaderNames"),
			outputItem("agents", "policy"), outputItem("agents", "runtimeType"),
		}
	}
	if key == "agent get" {
		return []auditPath{
			outputPath("data", "agent", "id"), outputPath("data", "agent", "name"),
			outputPath("data", "agent", "runtime"), outputPath("data", "agent", "status"),
			outputPath("data", "agent", "backendRegistered"), outputPath("data", "agent", "apiKeyConfigured"),
			outputPath("data", "agent", "configuredHeaderNames"), outputPath("data", "agent", "policy"),
			outputPath("data", "agent", "runtimeType"),
		}
	}
	paths := make([]auditPath, 0, len(selectors))
	seen := make(map[string]struct{}, len(selectors))
	for _, item := range selectors {
		for _, path := range item.Paths {
			if path.Root != auditOutputPath {
				continue
			}
			key := auditPathKey(path)
			if _, ok := seen[key]; ok {
				continue
			}
			seen[key] = struct{}{}
			paths = append(paths, path)
		}
	}
	if len(paths) == 0 {
		paths = append(paths, outputPath("data"))
	}
	return paths
}

func auditPathKey(path auditPath) string {
	var b strings.Builder
	if path.Root == auditInputPath {
		b.WriteString("in:")
	} else {
		b.WriteString("out:")
	}
	for _, segment := range path.Segments {
		b.WriteString(segment.Name)
		if segment.ArrayItems {
			b.WriteByte('[')
		}
		b.WriteByte('.')
	}
	return b.String()
}

func typedAuditFollowUp(key string) (auditFollowUp, bool) {
	listCursor := map[string]auditActionRef{
		"workspace list": actionRef("workspace", "list"), "project list": actionRef("project", "list"),
		"team list": actionRef("team", "list"), "channel list": actionRef("channel", "list"),
		"review list": actionRef("review", "list"), "role list": actionRef("role", "list"),
		"scheduled-message list": actionRef("scheduled-message", "list"), "scheduled-message runs": actionRef("scheduled-message", "runs"),
		"task list": actionRef("task", "list"),
	}
	if target, ok := listCursor[key]; ok {
		return cursorFollowUp(target, "repeat agentteam exec "+key+" with nextCursor; the registered cursor builder resumes after the returned page"), true
	}
	if key == "skill list" {
		return pageFollowUp(actionRef("skill", "list"), "repeat agentteam exec skill list with the registered page builder; the returned page is bounded"), true
	}
	switch key {
	case "project create":
		return readFollowUp(actionRef("project", "list"), auditBuilderByCursor, "agentteam exec project list with the returned project id or nextCursor", inputPath("cursor")), true
	case "project delete":
		return readFollowUp(actionRef("project", "list"), auditBuilderByCursor, "agentteam exec project list to confirm deletion", inputPath("cursor")), true
	case "agent list":
		return readFollowUp(actionRef("agent", "get"), auditBuilderByAgentID, "agentteam exec agent get with agentId from the page; the cursor revision remains bound", inputPath("agentId")), true
	case "agent get", "agent start", "agent stop", "agent restart", "agent update":
		return readFollowUp(actionRef("agent", "get"), auditBuilderByAgentID, "agentteam exec agent get with agentId", inputPath("agentId")), true
	case "agent create", "agent delete", "agent duplicate":
		return readFollowUp(actionRef("agent", "list"), auditBuilderByCursor, "agentteam exec agent list or get with the returned stable Agent ID", inputPath("cursor")), true
	case "team get", "team update":
		return readFollowUp(actionRef("team", "get"), auditBuilderByTeamID, "agentteam exec team get with teamId", inputPath("teamId")), true
	case "channel get", "channel members", "channel create", "channel update", "channel agent-add", "channel agent-remove":
		return readFollowUp(actionRef("channel", "get"), auditBuilderByChannelID, "agentteam exec channel get with channelId", inputPath("channelId")), true
	case "review add", "review delete":
		return readFollowUp(actionRef("review", "list"), auditBuilderByContextID, "agentteam exec review list with the registered thread/context selector", inputPath("thread")), true
	case "role get", "role create", "role update", "role delete", "role apply":
		return readFollowUp(actionRef("role", "request-get"), auditBuilderByRequestID, "agentteam exec role request-get with requestId, then role get with roleId", inputPath("requestId")), true
	case "role request-get":
		return readFollowUp(actionRef("role", "request-get"), auditBuilderByRequestID, "agentteam exec role request-get with requestId", inputPath("requestId")), true
	case "skill get", "skill create", "skill update", "skill import", "skill delete":
		return readFollowUp(actionRef("skill", "get"), auditBuilderBySkillID, "agentteam exec skill get with skillId", inputPath("skillId")), true
	case "profile set-avatar":
		return noFollowUp("no canonical read-only follow-up is registered for a local avatar replacement"), true
	case "task get", "task create", "task update", "task claim", "task unclaim", "task checkpoint", "task delete":
		return readFollowUp(actionRef("task", "get"), auditBuilderByTaskLocator, "agentteam exec task get with channel and number", inputPath("channel"), inputPath("number")), true
	case "scheduled-message get", "scheduled-message validate", "scheduled-message create", "scheduled-message update", "scheduled-message pause", "scheduled-message resume", "scheduled-message delete":
		return readFollowUp(actionRef("scheduled-message", "get"), auditBuilderByScheduleID, "agentteam exec scheduled-message get with id", inputPath("id")), true
	case "workflow plan", "workflow trigger", "workflow run", "workflow step":
		return noFollowUp("use the operation-specific receipt selector; no generic read action is registered"), true
	default:
		return auditFollowUp{}, false
	}
}

func typedAuditSelectors(key string) []auditSelector {
	outNext := outputPath("data", "nextCursor")
	switch key {
	case "workspace list":
		return selectors(selector("channel.name", outputItem("channels", "name")), selector("agent.machineId", outputItem("agents", "machineId")), selector("human.name", outputItem("humans", "name")), selector("nextCursor", outNext))
	case "project list":
		return selectors(selector("project.id", outputItem("projects", "id")), selector("nextCursor", outNext))
	case "project create":
		return selectors(selector("project.id", outputPath("data", "project", "id")))
	case "project delete":
		return selectors(selector("project.id", inputPath("id"), outputPath("data", "id")))
	case "agent list":
		return selectors(selector("agent.id", outputItem("agents", "id")), selector("nextCursor", outNext), selector("cursor.revision", inputPath("cursor")))
	case "agent get":
		return selectors(selector("agentId", inputPath("agentId")), selector("agent.id", outputPath("data", "agent", "id")))
	case "agent start", "agent stop", "agent restart":
		return selectors(selector("agentId", inputPath("agentId")), selector("requestId", inputPath("requestId")))
	case "agent create", "agent update", "agent delete", "agent duplicate":
		return selectors(selector("requestId", inputPath("requestId")), selector("approvalId", outputPath("data", "approvalId")))
	case "team list":
		return selectors(selector("teamId", outputItem("teams", "teamId")), selector("nextCursor", outNext))
	case "team get":
		return selectors(selector("teamId", inputPath("teamId")), selector("team.teamId", outputPath("data", "team", "teamId")))
	case "team update":
		return selectors(selector("teamId", inputPath("teamId")), selector("requestId", inputPath("requestId")))
	case "channel list":
		return selectors(selector("channelId", outputItem("channels", "channelId")), selector("nextCursor", outNext))
	case "channel get":
		return selectors(selector("channelId", inputPath("channelId")), selector("channel.channelId", outputPath("data", "channel", "channelId")))
	case "channel members":
		return selectors(selector("channelId", inputPath("channelId")), selector("nextCursor", outNext))
	case "channel create":
		return selectors(selector("channelId", outputPath("data", "channel", "channelId")), selector("requestId", inputPath("requestId")))
	case "channel update":
		return selectors(selector("channelId", inputPath("channelId"), outputPath("data", "channel", "channelId")), selector("requestId", inputPath("requestId")))
	case "channel agent-add", "channel agent-remove":
		return selectors(selector("channelId", inputPath("channelId"), outputPath("data", "channelId")), selector("requestId", inputPath("requestId")))
	case "review list":
		return selectors(selector("id", outputItem("contexts", "id")), selector("nextCursor", outNext))
	case "review add":
		return selectors(selector("id", outputPath("data", "context", "id")), selector("thread", inputPath("thread")))
	case "review delete":
		return selectors(selector("contextId", inputPath("contextId"), outputPath("data", "contextId")))
	case "role list":
		return selectors(selector("roleId", outputItem("roles", "roleId")), selector("nextCursor", outNext))
	case "role get":
		return selectors(selector("roleId", inputPath("roleId"), outputPath("data", "role", "roleId")))
	case "role request-get":
		return selectors(selector("requestId", inputPath("requestId"), outputPath("data", "requestId")))
	case "role create":
		return selectors(selector("requestId", inputPath("requestId")), selector("approvalId", outputPath("data", "approvalId")))
	case "role update", "role delete":
		return selectors(selector("requestId", inputPath("requestId")), selector("roleId", inputPath("roleId")), selector("approvalId", outputPath("data", "approvalId")))
	case "role apply":
		return selectors(selector("requestId", inputPath("requestId")), selector("roleId", inputPath("roleId")), selector("roleVersionId", inputPath("roleVersionId")), selector("agentId", inputPath("agentId")), selector("approvalId", outputPath("data", "approvalId")))
	case "skill list":
		return selectors(selector("id", outputItem("items", "id")), selector("page", inputPath("page")), selector("perPage", inputPath("perPage")))
	case "skill get":
		return selectors(selector("skillId", inputPath("skillId")), selector("id", outputPath("data", "id")))
	case "skill create":
		return selectors(selector("id", outputPath("data", "id")))
	case "skill update", "skill import":
		return selectors(selector("skillId", inputPath("skillId")))
	case "skill delete":
		return selectors(selector("skillId", inputPath("skillId")), selector("requestId", inputPath("requestId")), selector("approvalId", outputPath("data", "approvalId")))
	case "profile set-avatar":
		return selectors(selector("avatarUrl", outputPath("data", "avatarUrl")))
	case "task create":
		return selectors(selector("channel", inputPath("channel"), outputPath("data", "channelRef")), selector("taskNumber", outputItem("tasks", "taskNumber")))
	case "task get", "task update", "task checkpoint", "task delete":
		return selectors(selector("channel", inputPath("channel")), selector("number", inputPath("number")))
	case "task list":
		return selectors(selector("channelRef", outputPath("data", "channelRef")), selector("taskNumber", outputItem("tasks", "taskNumber")), selector("nextCursor", outNext))
	case "task claim", "task unclaim":
		return selectors(selector("channel", inputPath("channel")), selector("numbers", inputPath("numbers")))
	case "scheduled-message list":
		return selectors(selector("id", outputItem("items", "id")), selector("nextCursor", outNext))
	case "scheduled-message get", "scheduled-message validate":
		return selectors(selector("id", inputPath("id")))
	case "scheduled-message runs":
		return selectors(selector("id", inputPath("id")), selector("nextCursor", outNext))
	case "scheduled-message create":
		return selectors(selector("id", outputPath("data", "id")), selector("idempotencyKey", inputPath("idempotencyKey")))
	case "scheduled-message update":
		return selectors(selector("id", inputPath("id"), outputPath("data", "id")), selector("idempotencyKey", inputPath("idempotencyKey")))
	case "scheduled-message pause", "scheduled-message resume", "scheduled-message delete":
		return selectors(selector("id", inputPath("id"), outputPath("data", "id")))
	case "workflow plan":
		return selectors(selector("action", inputPath("action")), selector("planId", inputPath("planId")))
	case "workflow trigger":
		return selectors(selector("action", inputPath("action")), selector("triggerId", inputPath("triggerId")))
	case "workflow run":
		return selectors(selector("action", inputPath("action")), selector("runId", inputPath("runId")))
	case "workflow step":
		return selectors(selector("action", inputPath("action")), selector("runId", inputPath("runId")), selector("stepId", inputPath("stepId")), selector("idempotencyKey", inputPath("idempotencyKey")))
	default:
		return nil
	}
}
