package servicescfg

import (
	"fmt"
	"strings"
)

const (
	// APIVersionV1Alpha1 identifies current typed services.yaml contract version.
	APIVersionV1Alpha1 = "kodex.works/v1alpha1"
	// KindServiceStack is the root object kind for services config.
	KindServiceStack = "ServiceStack"
)

// RuntimeMode controls runtime execution profile for webhook-triggered runs.
type RuntimeMode string

const (
	RuntimeModeFullEnv  RuntimeMode = "full-env"
	RuntimeModeCodeOnly RuntimeMode = "code-only"
)

// NormalizeRuntimeMode validates and normalizes runtime mode values.
func NormalizeRuntimeMode(value RuntimeMode) (RuntimeMode, error) {
	v := RuntimeMode(strings.TrimSpace(strings.ToLower(string(value))))
	if v == "" {
		return "", nil
	}
	switch v {
	case RuntimeModeFullEnv, RuntimeModeCodeOnly:
		return v, nil
	default:
		return "", fmt.Errorf("unsupported runtime mode %q", value)
	}
}

// CodeUpdateStrategy controls how code updates become effective in non-prod runtime.
type CodeUpdateStrategy string

const (
	CodeUpdateStrategyHotReload CodeUpdateStrategy = "hot-reload"
	CodeUpdateStrategyRebuild   CodeUpdateStrategy = "rebuild"
	CodeUpdateStrategyRestart   CodeUpdateStrategy = "restart"
)

// NormalizeCodeUpdateStrategy validates and normalizes strategy values.
func NormalizeCodeUpdateStrategy(value CodeUpdateStrategy) (CodeUpdateStrategy, error) {
	v := CodeUpdateStrategy(strings.TrimSpace(strings.ToLower(string(value))))
	if v == "" {
		return CodeUpdateStrategyRebuild, nil
	}
	switch v {
	case CodeUpdateStrategyHotReload, CodeUpdateStrategyRebuild, CodeUpdateStrategyRestart:
		return v, nil
	default:
		return "", fmt.Errorf("unsupported codeUpdateStrategy %q", value)
	}
}

// ServiceScope controls whether service is deployed per environment or once per infrastructure.
type ServiceScope string

const (
	// ServiceScopeEnvironment deploys service in each target namespace.
	ServiceScopeEnvironment ServiceScope = "environment"
	// ServiceScopeInfrastructureSingleton deploys service only in platform namespace.
	ServiceScopeInfrastructureSingleton ServiceScope = "infrastructure-singleton"
)

// NormalizeServiceScope validates and normalizes service scope values.
func NormalizeServiceScope(value ServiceScope) (ServiceScope, error) {
	v := ServiceScope(strings.TrimSpace(strings.ToLower(string(value))))
	if v == "" {
		return ServiceScopeEnvironment, nil
	}
	switch v {
	case ServiceScopeEnvironment, ServiceScopeInfrastructureSingleton:
		return v, nil
	default:
		return "", fmt.Errorf("unsupported service scope %q", value)
	}
}

// Stack is a typed root contract for services.yaml.
type Stack struct {
	APIVersion string   `yaml:"apiVersion"`
	Kind       string   `yaml:"kind"`
	Metadata   Metadata `yaml:"metadata"`
	Spec       Spec     `yaml:"spec"`
}

// Metadata contains high-level stack identity.
type Metadata struct {
	Name string `yaml:"name"`
}

// Spec contains deployable stack definition.
type Spec struct {
	Project          string                          `yaml:"project,omitempty"`
	ProjectDocs      []ProjectDocRef                 `yaml:"projectDocs,omitempty"`
	RoleDocTemplates map[string][]RoleDocTemplateRef `yaml:"roleDocTemplates,omitempty"`
	Versions         map[string]VersionSpec          `yaml:"versions,omitempty"`
	Imports          []ImportRef                     `yaml:"imports,omitempty"`
	Components       []Component                     `yaml:"components,omitempty"`
	Environments     map[string]Environment          `yaml:"environments,omitempty"`
	WebhookRuntime   WebhookRuntime                  `yaml:"webhookRuntime,omitempty"`
	SecretResolution SecretResolution                `yaml:"secretResolution,omitempty"`
	Images           map[string]Image                `yaml:"images,omitempty"`
	Infrastructure   []InfrastructureItem            `yaml:"infrastructure,omitempty"`
	Services         []Service                       `yaml:"services,omitempty"`
	Orchestration    Orchestration                   `yaml:"orchestration,omitempty"`
}

// ImportRef points to reusable services.yaml fragment.
type ImportRef struct {
	Path string `yaml:"path"`
}

// Component declares reusable defaults.
type Component struct {
	Name            string           `yaml:"name"`
	ServiceDefaults *ServiceDefaults `yaml:"serviceDefaults,omitempty"`
}

// ServiceDefaults describes reusable service defaults.
type ServiceDefaults struct {
	CodeUpdateStrategy CodeUpdateStrategy `yaml:"codeUpdateStrategy,omitempty"`
	DeployGroup        string             `yaml:"deployGroup,omitempty"`
	DependsOn          []string           `yaml:"dependsOn,omitempty"`
}

// Environment configures environment-level defaults and namespace strategy.
type Environment struct {
	From              string `yaml:"from,omitempty"`
	NamespaceTemplate string `yaml:"namespaceTemplate,omitempty"`
	DomainTemplate    string `yaml:"domainTemplate,omitempty"`
	ImagePullPolicy   string `yaml:"imagePullPolicy,omitempty"`
}

// WebhookRuntime configures trigger->runtime mode mapping for webhook orchestration.
type WebhookRuntime struct {
	DefaultMode         RuntimeMode            `yaml:"defaultMode,omitempty"`
	TriggerModes        map[string]RuntimeMode `yaml:"triggerModes,omitempty"`
	DefaultNamespaceTTL string                 `yaml:"defaultNamespaceTTL,omitempty"`
	NamespaceTTLByRole  map[string]string      `yaml:"namespaceTTLByRole,omitempty"`
}

// SecretResolution configures environment-scoped secret override strategy.
type SecretResolution struct {
	EnvironmentAliases map[string][]string     `yaml:"environmentAliases,omitempty"`
	KeyOverrides       []SecretKeyOverrideRule `yaml:"keyOverrides,omitempty"`
	Patterns           []SecretOverridePattern `yaml:"patterns,omitempty"`
}

// SecretKeyOverrideRule binds one logical key to environment-specific override keys.
type SecretKeyOverrideRule struct {
	SourceKey    string            `yaml:"sourceKey"`
	OverrideKeys map[string]string `yaml:"overrideKeys,omitempty"`
}

// SecretOverridePattern derives override key names from source key and environment.
//
// Supported tokens in OverrideTemplate:
//   - {key}
//   - {suffix}
//   - {env}
//   - {env_upper}
type SecretOverridePattern struct {
	SourcePrefix     string   `yaml:"sourcePrefix,omitempty"`
	ExcludePrefixes  []string `yaml:"excludePrefixes,omitempty"`
	ExcludeSuffixes  []string `yaml:"excludeSuffixes,omitempty"`
	Environments     []string `yaml:"environments,omitempty"`
	OverrideTemplate string   `yaml:"overrideTemplate"`
}

// ProjectDocRef declares one documentation path to include in prompt context.
type ProjectDocRef struct {
	Repository  string   `yaml:"repository,omitempty"`
	Path        string   `yaml:"path"`
	Description string   `yaml:"description,omitempty"`
	Roles       []string `yaml:"roles,omitempty"`
	Optional    bool     `yaml:"optional,omitempty"`
}

// RoleDocTemplateRef declares one template path for role-specific artifact guidance.
type RoleDocTemplateRef struct {
	Repository  string `yaml:"repository,omitempty"`
	Path        string `yaml:"path"`
	Description string `yaml:"description,omitempty"`
}

// Image describes a stack image entry.
type Image struct {
	Type        string            `yaml:"type,omitempty"`
	From        string            `yaml:"from,omitempty"`
	Local       string            `yaml:"local,omitempty"`
	Repository  string            `yaml:"repository,omitempty"`
	TagTemplate string            `yaml:"tagTemplate,omitempty"`
	Dockerfile  string            `yaml:"dockerfile,omitempty"`
	Context     string            `yaml:"context,omitempty"`
	BuildArgs   map[string]string `yaml:"buildArgs,omitempty"`
}

// InfrastructureItem groups infra manifests and dependencies.
type InfrastructureItem struct {
	Name      string        `yaml:"name"`
	DependsOn []string      `yaml:"dependsOn,omitempty"`
	Manifests []ManifestRef `yaml:"manifests,omitempty"`
	When      string        `yaml:"when,omitempty"`
}

// ManifestRef points to one YAML manifest.
type ManifestRef struct {
	Path string `yaml:"path"`
}

// Service describes one deployable service.
type Service struct {
	Name               string             `yaml:"name"`
	Use                []string           `yaml:"use,omitempty"`
	CodeUpdateStrategy CodeUpdateStrategy `yaml:"codeUpdateStrategy,omitempty"`
	Scope              ServiceScope       `yaml:"scope,omitempty"`
	DeployGroup        string             `yaml:"deployGroup,omitempty"`
	DependsOn          []string           `yaml:"dependsOn,omitempty"`
	Manifests          []ManifestRef      `yaml:"manifests,omitempty"`
	When               string             `yaml:"when,omitempty"`
	Image              ServiceImage       `yaml:"image,omitempty"`
}

// ServiceImage defines how service image reference is built.
type ServiceImage struct {
	Repository  string `yaml:"repository,omitempty"`
	TagTemplate string `yaml:"tagTemplate,omitempty"`
}

// Orchestration defines global rollout and cleanup policy.
type Orchestration struct {
	DeployOrder   []string      `yaml:"deployOrder,omitempty"`
	CleanupPolicy CleanupPolicy `yaml:"cleanupPolicy,omitempty"`
}

// CleanupPolicy defines cleanup behaviors for runtime environments.
type CleanupPolicy struct {
	FullEnvIdleTTL string `yaml:"fullEnvIdleTTL,omitempty"`
}

// ResolvedContext is final context used for template rendering.
type ResolvedContext struct {
	Env       string
	Namespace string
	Project   string
	Slot      int
	Vars      map[string]string
	Versions  map[string]string
}

// LoadOptions controls services.yaml rendering behavior.
type LoadOptions struct {
	Env       string
	Namespace string
	Slot      int
	Vars      map[string]string
}

// LoadResult returns typed stack plus effective render context.
type LoadResult struct {
	Stack   *Stack
	Context ResolvedContext
	RawYAML []byte
}
