package dsl

import (
	"sort"
	"strings"
)

const (
	// AgentTeamPublishTreeUse publishes a staged file tree into an AGS repository.
	AgentTeamPublishTreeUse = "agentteam/publish-tree"

	AgentTeamPublishTreeWithRepository  = "repository"
	AgentTeamPublishTreeWithSourcePath  = "source_path"
	AgentTeamPublishTreeWithMessage     = "message"
	AgentTeamPublishTreeWithDescription = "description"
	AgentTeamPublishTreeWithMaxFiles    = "max_files"
)

// AgentTeamPublishTreeOptions are the normalized options for a agentteam/publish-tree step.
type AgentTeamPublishTreeOptions struct {
	Repository  string
	SourcePath  string
	Message     string
	Description string
	MaxFiles    int
}

// AgentTeamPublishTreeOptionError describes one invalid agentteam/publish-tree option.
type AgentTeamPublishTreeOptionError struct {
	Code    string
	Key     string
	Message string
}

func (e AgentTeamPublishTreeOptionError) Error() string {
	return e.Message
}

// ParseAgentTeamPublishTreeOptions validates and normalizes agentteam/publish-tree with values.
func ParseAgentTeamPublishTreeOptions(values map[string]any) (AgentTeamPublishTreeOptions, []AgentTeamPublishTreeOptionError) {
	options := AgentTeamPublishTreeOptions{SourcePath: "."}
	keys := make([]string, 0, len(values))
	for key := range values {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	var errs []AgentTeamPublishTreeOptionError
	for _, key := range keys {
		value := values[key]
		switch key {
		case AgentTeamPublishTreeWithRepository:
			text, ok := stringOption(value)
			if !ok || !validAgentTeamPublishRepository(text) {
				errs = append(errs, AgentTeamPublishTreeOptionError{
					Code:    "agentteam_publish_tree_repository_invalid",
					Key:     key,
					Message: "agentteam/publish-tree with.repository must be owner/repo",
				})
				continue
			}
			options.Repository = text
		case AgentTeamPublishTreeWithSourcePath:
			text, ok := stringOption(value)
			if !ok || !validAgentTeamPublishSourcePath(text) {
				errs = append(errs, AgentTeamPublishTreeOptionError{
					Code:    "agentteam_publish_tree_source_path_invalid",
					Key:     key,
					Message: "agentteam/publish-tree with.source_path must be a relative path outside .git control directories",
				})
				continue
			}
			options.SourcePath = text
		case AgentTeamPublishTreeWithMessage:
			text, ok := stringOption(value)
			if !ok {
				errs = append(errs, AgentTeamPublishTreeOptionError{Code: "agentteam_publish_tree_message_invalid", Key: key, Message: "agentteam/publish-tree with.message must be a string"})
				continue
			}
			options.Message = text
		case AgentTeamPublishTreeWithDescription:
			text, ok := stringOption(value)
			if !ok {
				errs = append(errs, AgentTeamPublishTreeOptionError{Code: "agentteam_publish_tree_description_invalid", Key: key, Message: "agentteam/publish-tree with.description must be a string"})
				continue
			}
			options.Description = text
		case AgentTeamPublishTreeWithMaxFiles:
			maxFiles, ok := intOption(value)
			if !ok || maxFiles <= 0 {
				errs = append(errs, AgentTeamPublishTreeOptionError{Code: "agentteam_publish_tree_max_files_invalid", Key: key, Message: "agentteam/publish-tree with.max_files must be a positive integer"})
				continue
			}
			options.MaxFiles = maxFiles
		default:
			errs = append(errs, AgentTeamPublishTreeOptionError{
				Code:    "agentteam_publish_tree_with_unsupported",
				Key:     key,
				Message: "agentteam/publish-tree only supports with.repository, with.source_path, with.message, with.description, and with.max_files",
			})
		}
	}
	if strings.TrimSpace(options.Repository) == "" {
		errs = append(errs, AgentTeamPublishTreeOptionError{
			Code:    "agentteam_publish_tree_repository_required",
			Key:     AgentTeamPublishTreeWithRepository,
			Message: "agentteam/publish-tree with.repository is required",
		})
	}
	return options, errs
}
