package vsphere

import (
	"context"

	rigv1 "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1"
	vspheretpl "vanderlande.com/ittp/appstack/rig-operator/internal/templates/vsphere"
)

type Strategy struct {
	blueprint  *rigv1.VsphereBlueprint
	userData   string
	rancherURL string
	defaults   vspheretpl.Defaults
}

// NewStrategy creates the vSphere logic handler
func NewStrategy(vbp *rigv1.VsphereBlueprint, userData string, rancherURL string, defaults vspheretpl.Defaults) *Strategy {
	// 1. Resolve UserData (Infra > Template Default)
	finalUserData := userData
	if finalUserData == "" {
		finalUserData = defaults.UserData
	}

	return &Strategy{
		blueprint:  vbp,
		userData:   finalUserData,
		rancherURL: rancherURL,
		defaults:   defaults,
	}
}

// GenerateNodePools maps the generic ClusterBlueprint to vSphere-specific NodePool maps
func (s *Strategy) GenerateNodePools(ctx context.Context, cbp *rigv1.ClusterBlueprint) (interface{}, error) {
	var nodePools []map[string]interface{}

	// 1. Control Plane Node Pool
	// We rely on the defaults extracted from values.yaml (e.g. 4 Core, 8GB)
	// vSphere Chart expects MB, so we multiply GB * 1024.
	cpQty := 1
	if cbp.Spec.ControlPlaneHA {
		cpQty = 3
	}

	nodePools = append(nodePools, s.buildPool(
		"control-plane-nodes",   // Name
		"cp-nodes",              // Display Name
		cpQty,                   // Quantity
		s.defaults.CP_CPU,       // Cores
		s.defaults.CP_Mem*1024,  // RAM (GB -> MB)
		s.defaults.CP_Disk*1024, // Disk (GB -> MB)
		true,                    // Etcd
		true,                    // ControlPlane
		false,                   // Worker
	))

	// 2. Worker Pools
	// We iterate over the user's requested pools in the CBP
	for _, wp := range cbp.Spec.WorkerPools {
		nodePools = append(nodePools, s.buildPool(
			wp.Name,
			wp.Name,
			wp.Quantity,
			wp.CpuCores,
			wp.MemoryGB*1024, // Convert GB to MB
			wp.DiskGB*1024,   // Convert GB to MB
			false,            // Etcd
			false,            // ControlPlane
			true,             // Worker
		))
	}

	return nodePools, nil
}

// GetGlobalOverrides injects the vSphere-specific global values (Cloud Provider, Credentials, URLs)
func (s *Strategy) GetGlobalOverrides(ctx context.Context, cbp *rigv1.ClusterBlueprint, credentialSecret string) (map[string]interface{}, error) {
	overrides := map[string]interface{}{
		// Tell Helm we are on vSphere
		"cloudprovider": "vsphere",

		// The Secret containing username/password/vcenter-address
		"cloudCredentialSecretName": credentialSecret,

		// Register with the correct Rancher Manager
		"rancher": map[string]interface{}{
			"cattle": map[string]interface{}{
				"url": s.rancherURL,
			},
		},

		// Cluster Metadata
		"cluster": map[string]interface{}{
			"name": cbp.Name,
			"config": map[string]interface{}{
				"kubernetesVersion": cbp.Spec.KubernetesVersion,
			},
		},
	}

	return overrides, nil
}

// buildPool is a private helper to construct the exact map structure the vSphere Helm Chart expects
func (s *Strategy) buildPool(name, displayName string, qty, cpu, ramMB, diskMB int, etcd, cp, worker bool) map[string]interface{} {
	pool := map[string]interface{}{
		// Generic RKE2 Node Settings
		"name":         name,
		"displayName":  displayName,
		"quantity":     qty,
		"etcd":         etcd,
		"controlplane": cp,
		"worker":       worker,
		"paused":       false,

		// vSphere Infrastructure Location (From Blueprint)
		"vcenter":          s.blueprint.Spec.VCenter,
		"datacenter":       s.blueprint.Spec.Datacenter,
		"folder":           s.blueprint.Spec.Folder,
		"pool":             s.blueprint.Spec.ResourcePool,
		"datastoreCluster": s.blueprint.Spec.Datastore, // Assumes chart supports this key. If not, use "datastore".
		"network":          []string{s.blueprint.Spec.Network},

		// Cloning Details
		"creationType": "template",
		"cloneFrom":    s.blueprint.Spec.Template,

		// Hardware Sizing (Already converted to MB)
		"cpuCount":   cpu,
		"memorySize": ramMB,
		"diskSize":   diskMB,

		// Cloud Init
		"cloudConfig": s.userData,
	}

	return pool
}
