package utils

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

const (
	// VMIDMin is the minimum valid Proxmox VM ID
	VMIDMin = 100
	// VMIDMax is the maximum valid Proxmox VM ID
	VMIDMax = 999999999
	// VMMinMemoryMB is the minimum memory for a VM (128MB)
	VMMinMemoryMB = 128
	// VMMaxMemoryMB is a reasonable maximum memory (2TB)
	VMMaxMemoryMB = 2 * 1024 * 1024
	// VMMinDiskGB is the minimum disk size (1GB)
	VMMinDiskGB = 1
	// VMMaxDiskGB is a reasonable maximum disk size (100TB)
	VMMaxDiskGB = 100 * 1024
)

// ValidateVMID validates that a VM ID is within valid Proxmox range
func ValidateVMID(vmid int) error {
	if vmid < VMIDMin || vmid > VMIDMax {
		return fmt.Errorf("VMID %d is out of valid range (%d-%d)", vmid, VMIDMin, VMIDMax)
	}
	return nil
}

// ValidateVMName validates a VM name according to Proxmox restrictions
// Proxmox VM names must:
// - Be 1-100 characters long
// - Only contain alphanumeric characters, hyphens, underscores, dots, and spaces
// - Not start or end with spaces
func ValidateVMName(name string) error {
	if len(name) == 0 {
		return fmt.Errorf("VM name cannot be empty")
	}

	if len(name) > 100 {
		return fmt.Errorf("VM name '%s' exceeds maximum length of 100 characters", name)
	}

	// Proxmox allows: alphanumeric, hyphen, underscore, dot, space
	// But spaces cannot be at start or end
	name = strings.TrimSpace(name)
	if len(name) != len(strings.TrimSpace(name)) {
		return fmt.Errorf("VM name cannot start or end with spaces")
	}

	// Valid characters: alphanumeric, hyphen, underscore, dot, space (but not at edges)
	validPattern := regexp.MustCompile(`^[a-zA-Z0-9._-]+( [a-zA-Z0-9._-]+)*$`)
	if !validPattern.MatchString(name) {
		return fmt.Errorf("VM name '%s' contains invalid characters. Allowed: alphanumeric, hyphen, underscore, dot, space", name)
	}

	return nil
}

// ValidateMemory validates memory specification
func ValidateMemory(memory string) error {
	if memory == "" {
		return fmt.Errorf("memory cannot be empty")
	}

	memoryMB := ParseMemoryToMB(memory)
	if memoryMB < VMMinMemoryMB {
		return fmt.Errorf("memory %s (%d MB) is below minimum of %d MB", memory, memoryMB, VMMinMemoryMB)
	}
	if memoryMB > VMMaxMemoryMB {
		return fmt.Errorf("memory %s (%d MB) exceeds maximum of %d MB", memory, memoryMB, VMMaxMemoryMB)
	}

	return nil
}

// ValidateDisk validates disk specification
func ValidateDisk(disk string) error {
	if disk == "" {
		return fmt.Errorf("disk cannot be empty")
	}

	diskGB := ParseDiskToGB(disk)
	if diskGB < VMMinDiskGB {
		return fmt.Errorf("disk %s (%d GB) is below minimum of %d GB", disk, diskGB, VMMinDiskGB)
	}
	if diskGB > VMMaxDiskGB {
		return fmt.Errorf("disk %s (%d GB) exceeds maximum of %d GB", disk, diskGB, VMMaxDiskGB)
	}

	return nil
}

// ValidateCPU validates CPU count
func ValidateCPU(cpu int) error {
	if cpu < 1 {
		return fmt.Errorf("CPU count must be at least 1, got %d", cpu)
	}
	// Reasonable maximum: 1024 cores
	if cpu > 1024 {
		return fmt.Errorf("CPU count %d exceeds maximum of 1024", cpu)
	}
	return nil
}

// ValidateNetworkBridge validates network bridge name format
// Network bridges typically follow vmbrX pattern or custom names
func ValidateNetworkBridge(network string) error {
	if network == "" {
		return fmt.Errorf("network bridge cannot be empty")
	}

	// Basic validation: alphanumeric, hyphen, underscore (common bridge naming)
	validPattern := regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
	if !validPattern.MatchString(network) {
		return fmt.Errorf("network bridge name '%s' contains invalid characters", network)
	}

	return nil
}

// ValidateImageSpec validates image specification format
// Images can be:
// - Numeric VMID (for template cloning): "123"
// - Volid format: "storage:path/to/image"
// - Image name: "ubuntu-22.04-cloud"
func ValidateImageSpec(image string) error {
	if image == "" {
		return fmt.Errorf("image cannot be empty")
	}

	// Check if it's a numeric VMID (template)
	if vmid, err := strconv.Atoi(image); err == nil {
		if err := ValidateVMID(vmid); err != nil {
			return fmt.Errorf("invalid template VMID: %w", err)
		}
		return nil
	}

	// Check if it's a volid format (storage:path)
	if strings.Contains(image, ":") {
		parts := strings.SplitN(image, ":", 2)
		if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
			return fmt.Errorf("invalid volid format '%s', expected 'storage:path'", image)
		}
		return nil
	}

	// Otherwise assume it's an image name (validate basic format)
	if len(image) > 255 {
		return fmt.Errorf("image name '%s' exceeds maximum length of 255 characters", image)
	}

	return nil
}

