// Package kustomize generates Kustomize overlays from real staging ArgoCD
// configs, patching DB/AWS/service endpoints for the local k3d environment.
package kustomize

import (
	"fmt"
	"strings"

	"github.com/tidbcloud/controlplane9/internal/config"
	"github.com/tidbcloud/controlplane9/internal/persona"
)

// OverlayInput holds all inputs needed to generate overlays for a set of services.
type OverlayInput struct {
	// Plan is the resolved persona plan containing per-service roles.
	Plan *persona.Plan

	// Images maps service name → local image reference built for this session.
	Images map[string]string

	// DSNs maps service name → MySQL DSN string.
	DSNs map[string]string

	// AWS holds the AWS configuration for the local environment.
	AWS config.AWSConfig

	// Owner / Session are injected into overlays so services can propagate the
	// default cp9 tag invariant at runtime.
	Owner   string
	Session string

	// Namespace is the target session namespace for generated overlays
	// (default: "default"). All namespaced staging resources are materialized
	// into this namespace on the selected host.
	Namespace string

	// StagingConfigs maps service name → parsed staging config.
	// If nil, overlays are generated without a staging base (patches only).
	StagingConfigs map[string]*StagingConfig

	// StagingRoot is the local app-delivery checkout root used to resolve
	// relative Kustomize base paths into the generated overlay tree.
	StagingRoot string
}

// StagingConfig represents a parsed staging ArgoCD Application manifest
// for a single service. It captures the fields we need to patch.
type StagingConfig struct {
	// Name is the service name (e.g. "billing-svc").
	Name string `json:"name"`

	// Namespace is the source/staging namespace declared by the ArgoCD
	// Application. It is informative input only; generated overlays deploy into
	// OverlayInput.Namespace instead of preserving the staging namespace.
	Namespace string `json:"namespace"`

	// Image is the container image reference (e.g. "gcr.io/tidb/billing-svc:latest").
	Image string `json:"image,omitempty"`

	// Env holds environment variables from the staging Deployment spec.
	Env map[string]string `json:"env,omitempty"`

	// Ports maps port name → port number (e.g. "grpc" → 50051, "http" → 8080).
	Ports map[string]int `json:"ports,omitempty"`

	// KustomizePath is the relative path within app-delivery to the kustomization base.
	KustomizePath string `json:"kustomize_path,omitempty"`

	// WorkloadKind is the primary rollout object kind (Deployment / StatefulSet).
	WorkloadKind string `json:"workload_kind,omitempty"`

	// WorkloadName is the primary rollout object name to patch / watch.
	WorkloadName string `json:"workload_name,omitempty"`

	// ContainerName is the primary container name inside the rollout object.
	ContainerName string `json:"container_name,omitempty"`
}

// Patch represents a single Kustomize JSON patch operation.
type Patch struct {
	Op    string `json:"op"`
	Path  string `json:"path"`
	Value any    `json:"value,omitempty"`
}

// ServiceOverlay holds the generated overlay for a single service.
type ServiceOverlay struct {
	// Service name.
	Name string

	// Role is the resolved service-plan role (source/live/stub/skip).
	Role persona.Role

	// Namespace for deployment.
	Namespace string

	// KustomizeBase is the relative path to the staging kustomize base.
	// Used as the resources entry in kustomization.yaml.
	KustomizeBase string

	// Image is the session-local image reference to deploy.
	Image string

	// WorkloadKind / WorkloadName / ContainerName identify the primary object to patch.
	WorkloadKind  string
	WorkloadName  string
	ContainerName string

	// Ports is the normalized set of service ports for synthetic overlays and readiness.
	Ports map[string]int

	// Synthetic indicates that cp9 generated a self-contained Deployment/Service
	// because no staging base exists for this service in the current session.
	Synthetic bool

	// Patches is the list of JSON patches to apply to the base deployment.
	Patches []Patch

	// EnvPatches maps env var name → value for environment variable patches.
	EnvPatches map[string]string

	// Volumes / VolumeMounts are added to the workload pod template when a
	// service needs selected-host-backed storage.
	Volumes      []VolumeSpec
	VolumeMounts []VolumeMount
}

type VolumeSpec struct {
	Name     string
	HostPath string
}

type VolumeMount struct {
	Name      string
	MountPath string
}

// GenerateResult is the structured output for overlay generation.
type GenerateResult struct {
	OutputDir string                   `json:"output_dir"`
	Services  []string                 `json:"services"`
	Skipped   []string                 `json:"skipped,omitempty"`
	Overlays  map[string]OverlayResult `json:"overlays,omitempty"`
}

// OverlayResult captures the generated rollout metadata for a single service.
type OverlayResult struct {
	Name          string         `json:"name"`
	Role          persona.Role   `json:"role"`
	Directory     string         `json:"directory"`
	Namespace     string         `json:"namespace"`
	Image         string         `json:"image,omitempty"`
	WorkloadKind  string         `json:"workload_kind,omitempty"`
	WorkloadName  string         `json:"workload_name,omitempty"`
	ContainerName string         `json:"container_name,omitempty"`
	Ports         map[string]int `json:"ports,omitempty"`
	Synthetic     bool           `json:"synthetic,omitempty"`
}

// FormatText implements model.TextFormatter.
func (r *GenerateResult) FormatText() string {
	var b strings.Builder
	fmt.Fprintf(&b, "kustomize: generated overlays for %d services in %s", len(r.Services), r.OutputDir)
	if len(r.Skipped) > 0 {
		fmt.Fprintf(&b, " (skipped %d: %s)", len(r.Skipped), strings.Join(r.Skipped, ", "))
	}
	return b.String()
}
