// Package persona implements service-plan loading for the Premium Reserved
// narrow wedge.
//
// New code should treat v1alpha2 `cp9.yaml` as the primary source of truth for
// the service graph (`source` / `live` / `stub`). Legacy persona/topology YAML
// remains compatibility-only during the train so older tests and helpers can be
// migrated slice by slice.
//
// File layout:
//
//	topologies/
//	  premium-reserved.yaml   # one file per persona; filename matches `persona` field
package persona

// Role classifies how a service is deployed for a session.
type Role string

const (
	RoleSource Role = "source"
	RoleLive   Role = "live"
	RoleStub   Role = "stub"
	RoleSkip   Role = "skip"

	// Deprecated aliases kept during the #106 train so older helpers and tests
	// continue to compile while the runtime is moved to source/live/stub.
	RoleReal Role = RoleSource
)

// Capability names that personas may request via `requires:`.
//
// Adding a new capability: extend the constant list AND ValidCapabilities
// below (single source of truth Validate consumes), and document the contract
// in the design doc.
const (
	CapCPCloud     = "cp-cloud"     // C1 + C2 — tunnel + crossplane reachable
	CapMetadb      = "metadb"       // Zero / Starter / local-mysql metadb provider healthy
	CapCRDsStaging = "crds-staging" // CRD subset dumped from staging available locally
)

// ValidCapabilities is the canonical set of capability names Validate accepts
// in `requires:`. Keep this in sync with the Cap* constants above.
var ValidCapabilities = []string{CapCPCloud, CapMetadb, CapCRDsStaging}

// Cloud names that personas may target via `clouds:`.
const (
	CloudAWS      = "aws"
	CloudGCP      = "gcp"
	CloudAzure    = "azure"
	CloudAlicloud = "alicloud"
)

// ValidClouds is the canonical set of cloud names Validate accepts in
// `clouds:`. Keep this in sync with the Cloud* constants above.
var ValidClouds = []string{CloudAWS, CloudGCP, CloudAzure, CloudAlicloud}

// Persona is the declarative template parsed from topologies/<name>.yaml.
type Persona struct {
	Persona  string   `yaml:"persona"            json:"persona"`
	Owners   []string `yaml:"owners,omitempty"   json:"owners,omitempty"`
	Real     []string `yaml:"real,omitempty"     json:"real,omitempty"`
	Stub     []string `yaml:"stub,omitempty"     json:"stub,omitempty"`
	Requires []string `yaml:"requires,omitempty" json:"requires,omitempty"`
	Clouds   []string `yaml:"clouds,omitempty"   json:"clouds,omitempty"`
}

// SourceRef points at the local source for a source-built service.
//
// Path must point at the service's main-package entry file, e.g.:
//
//	../tidb-management-service/cmd/tidb-mgmt-portal/main.go
//
// Pointing at the file (not the repo or package directory) disambiguates
// services in repos that host many main packages — the build context is
// derived as filepath.Dir(Path) and the service identity is encoded in the
// directory name. Ref is the optional git ref (branch, tag, sha) the
// developer expects to be checked out.
type SourceRef struct {
	Path string `json:"path"`
	Repo string `json:"repo,omitempty"`
	Ref  string `json:"ref,omitempty"`
	Main string `json:"main,omitempty"`
}

// AppRef points at the app-delivery contract for a source or live service.
type AppRef struct {
	Name     string `json:"name,omitempty"`
	Registry string `json:"registry,omitempty"`
	Env      string `json:"env,omitempty"`
}

// StubRef captures stub-specific generation metadata.
type StubRef struct {
	Kind    string `json:"kind,omitempty"`
	Swagger string `json:"swagger,omitempty"`
	Proto   string `json:"proto,omitempty"`
	Output  string `json:"output,omitempty"`
}

// ServicePlan is one service entry in the per-run plan artifact.
type ServicePlan struct {
	Name      string            `json:"name"`
	Role      Role              `json:"role"`
	Source    *SourceRef        `json:"source,omitempty"`
	App       *AppRef           `json:"app,omitempty"`
	Stub      *StubRef          `json:"stub,omitempty"`
	Overrides []string          `json:"overrides,omitempty"`
	ExtraEnv  map[string]string `json:"extra_env,omitempty"`
}

// Plan is the resolved service graph consumed by later lifecycle slices.
//
// For v1alpha2 sessions this is derived directly from unified `cp9.yaml`.
// Legacy persona/topology YAML can still populate it via BuildPlan while the
// migration remains in flight.
type Plan struct {
	Persona      string        `json:"persona"`
	Owners       []string      `json:"owners,omitempty"`
	Capabilities []string      `json:"capabilities,omitempty"`
	Clouds       []string      `json:"clouds,omitempty"`
	Services     []ServicePlan `json:"services"`
}

// LocalOverrides captures the per-developer view of a persona, sourced from
// `cp9.local.yaml`. Fields are optional; missing fields fall back to the
// persona template defaults.
type LocalOverrides struct {
	// Sources maps service name → checkout path + git ref.
	Sources map[string]SourceRef
	// ForceReal lists services to deploy REAL even if the persona marks them STUB.
	ForceReal []string
	// ForceStub lists services to deploy STUB even if the persona marks them REAL.
	ForceStub []string
	// ExtraEnv provides per-service env additions applied during `config_gen`.
	ExtraEnv map[string]map[string]string
}
