package gitops

// source_config JSON keys this package can overlay. Kept as constants so the
// apply, merge, and drift paths agree on the exact key strings.
const (
	keyPort           = "port"
	keyHealthcheck    = "healthcheck"
	keyDeployStrategy = "deploy_strategy"
)

// Source kinds eligible for GitOps in v1 (git-backed sources only).
const (
	SourceDockerfile = "dockerfile"
	SourceStatic     = "static"
)

// supportedKeys returns the source_config keys a given source kind accepts
// from a .tinyforge.yml overlay. A field declared in the file but not in this
// set is ignored (not applied, not drift-compared) so a shared file can target
// either source without producing dead keys or false drift.
//
// dockerfile: port + healthcheck + deploy_strategy (its real run knobs).
// static:     deploy_strategy only (a static site has no port/healthcheck).
func supportedKeys(sourceKind string) map[string]bool {
	switch sourceKind {
	case SourceDockerfile:
		return map[string]bool{keyPort: true, keyHealthcheck: true, keyDeployStrategy: true}
	case SourceStatic:
		return map[string]bool{keyDeployStrategy: true}
	default:
		return nil
	}
}

// IsEligibleSource reports whether GitOps may be enabled for a source kind.
func IsEligibleSource(sourceKind string) bool {
	return supportedKeys(sourceKind) != nil
}

// ApplyPlan is the typed, multi-target plan for applying an overlay. In v1 only
// SourceConfigPatch is populated; EnvUpserts/Faces are reserved so env (the
// workload_env table) and faces (the public_faces column) can be added later
// without reshaping the apply path — they are NOT in v1 (env would re-open the
// secrets-in-repo hole; faces live in a sibling store).
type ApplyPlan struct {
	// SourceConfigPatch holds the source_config keys to overlay onto the live
	// config. Only keys supported by the target source are present.
	SourceConfigPatch map[string]any

	// reserved for future phases — see package doc.
	// EnvUpserts []store.WorkloadEnv
	// Faces      []plugin.PublicFace
}

// declaredValues returns the present (non-nil) overlay fields keyed by their
// source_config JSON key, before the per-source filter. Shared by BuildPlan and
// Drift so they agree on what the file declared.
func declaredValues(spec Spec) map[string]any {
	out := map[string]any{}
	if spec.Deploy.Port != nil {
		out[keyPort] = *spec.Deploy.Port
	}
	if spec.Deploy.Healthcheck != nil {
		out[keyHealthcheck] = *spec.Deploy.Healthcheck
	}
	if spec.Deploy.DeployStrategy != nil {
		out[keyDeployStrategy] = *spec.Deploy.DeployStrategy
	}
	return out
}

// BuildPlan maps the present, source-supported overlay fields to a patch for
// the given source kind. Unsupported/absent fields are dropped.
func BuildPlan(spec Spec, sourceKind string) ApplyPlan {
	allowed := supportedKeys(sourceKind)
	patch := map[string]any{}
	for k, v := range declaredValues(spec) {
		if allowed[k] {
			patch[k] = v
		}
	}
	return ApplyPlan{SourceConfigPatch: patch}
}
