package scaling

import (
	"context"
	"fmt"
	"time"

	"github.com/pkg/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"github.com/sankofa/crossplane-provider-proxmox/apis/v1alpha1"
	"github.com/sankofa/crossplane-provider-proxmox/pkg/proxmox"
)

// InstanceManager manages VM instances in a scale set
type InstanceManager struct {
	proxmoxClient *proxmox.Client
}

// NewInstanceManager creates a new instance manager
func NewInstanceManager(client *proxmox.Client) *InstanceManager {
	return &InstanceManager{
		proxmoxClient: client,
	}
}

// CreateInstance creates a new VM instance from template
func (m *InstanceManager) CreateInstance(
	ctx context.Context,
	template v1alpha1.ProxmoxVMParameters,
	instanceName string,
) (*v1alpha1.VMInstance, error) {
	// Generate unique name if not provided
	if instanceName == "" {
		instanceName = fmt.Sprintf("%s-%d", template.Name, time.Now().Unix())
	}

	// Create VM spec from template
	vmSpec := proxmox.VMSpec{
		Node:    template.Node,
		Name:    instanceName,
		CPU:     template.CPU,
		Memory:  template.Memory,
		Disk:    template.Disk,
		Storage: template.Storage,
		Network: template.Network,
		Image:   template.Image,
	}

	// Create VM
	vm, err := m.proxmoxClient.CreateVM(ctx, vmSpec)
	if err != nil {
		return nil, errors.Wrap(err, "failed to create VM instance")
	}

	// Wait for VM to be ready (simplified - would need proper health checks)
	time.Sleep(5 * time.Second)

	// Get VM status
	status, err := m.proxmoxClient.GetVMStatus(ctx, vm.ID)
	if err != nil {
		return nil, errors.Wrap(err, "failed to get VM status")
	}

	instance := &v1alpha1.VMInstance{
		VMID:      vm.ID,
		Name:      instanceName,
		State:     status.State,
		IPAddress: status.IPAddress,
		CreatedAt: metav1.Now(),
	}

	return instance, nil
}

// DeleteInstance deletes a VM instance
func (m *InstanceManager) DeleteInstance(ctx context.Context, vmID int) error {
	return m.proxmoxClient.DeleteVM(ctx, vmID)
}

// GetInstanceStatus gets the status of a VM instance
func (m *InstanceManager) GetInstanceStatus(
	ctx context.Context,
	vmID int,
	node string,
) (*v1alpha1.VMInstance, error) {
	status, err := m.proxmoxClient.GetVMStatus(ctx, vmID)
	if err != nil {
		return nil, errors.Wrap(err, "failed to get VM status")
	}

	// Get VM details (would need additional API call)
	instance := &v1alpha1.VMInstance{
		VMID:      vmID,
		State:     status.State,
		IPAddress: status.IPAddress,
	}

	return instance, nil
}

// HealthCheck performs a health check on a VM instance
func (m *InstanceManager) HealthCheck(
	ctx context.Context,
	instance v1alpha1.VMInstance,
) bool {
	status, err := m.proxmoxClient.GetVMStatus(ctx, instance.VMID)
	if err != nil {
		return false
	}

	// VM is healthy if it's running
	return status.State == "running"
}

// ScaleTo scales the scale set to the desired number of replicas
func (m *InstanceManager) ScaleTo(
	ctx context.Context,
	template v1alpha1.ProxmoxVMParameters,
	currentInstances []v1alpha1.VMInstance,
	desiredReplicas int,
) ([]v1alpha1.VMInstance, error) {
	currentCount := len(currentInstances)
	
	if desiredReplicas == currentCount {
		return currentInstances, nil
	}

	var newInstances []v1alpha1.VMInstance

	if desiredReplicas > currentCount {
		// Scale up
		toCreate := desiredReplicas - currentCount
		for i := 0; i < toCreate; i++ {
			instanceName := fmt.Sprintf("%s-%d", template.Name, time.Now().UnixNano()+int64(i))
			instance, err := m.CreateInstance(ctx, template, instanceName)
			if err != nil {
				return nil, errors.Wrapf(err, "failed to create instance %d", i+1)
			}
			newInstances = append(newInstances, *instance)
		}
		newInstances = append(newInstances, currentInstances...)
	} else {
		// Scale down
		toDelete := currentCount - desiredReplicas
		instancesToKeep := currentInstances[:desiredReplicas]
		instancesToDelete := currentInstances[desiredReplicas:]

		for _, instance := range instancesToDelete[:toDelete] {
			if err := m.DeleteInstance(ctx, instance.VMID); err != nil {
				// Log error but continue
				fmt.Printf("Failed to delete instance %d: %v\n", instance.VMID, err)
			}
		}

		newInstances = instancesToKeep
	}

	return newInstances, nil
}

