package runtime

import (
	"fmt"
	"os"

	"chorus.services/bzzz/pkg/config"
)

// ConfigValidator validates configuration for specific binary types
type ConfigValidator struct {
	binaryType BinaryType
}

// NewConfigValidator creates a new config validator
func NewConfigValidator(binaryType BinaryType) *ConfigValidator {
	return &ConfigValidator{
		binaryType: binaryType,
	}
}

// ValidateForBinary validates configuration for the specified binary type
func (v *ConfigValidator) ValidateForBinary(cfg *config.Config) error {
	// Common validation
	if err := v.validateCommonConfig(cfg); err != nil {
		return fmt.Errorf("common config validation failed: %w", err)
	}

	// Binary-specific validation
	switch v.binaryType {
	case BinaryTypeAgent:
		return v.validateAgentConfig(cfg)
	case BinaryTypeHAP:
		return v.validateHAPConfig(cfg)
	default:
		return fmt.Errorf("unknown binary type: %v", v.binaryType)
	}
}

// validateCommonConfig validates common configuration for all binary types
func (v *ConfigValidator) validateCommonConfig(cfg *config.Config) error {
	if cfg == nil {
		return fmt.Errorf("configuration is nil")
	}

	// Validate agent configuration
	if cfg.Agent.ID == "" {
		return fmt.Errorf("agent ID is required")
	}

	// Validate basic capabilities
	if len(cfg.Agent.Capabilities) == 0 {
		return fmt.Errorf("at least one capability is required")
	}

	// P2P validation is handled in the main config validation

	return nil
}

// validateAgentConfig validates agent-specific configuration
func (v *ConfigValidator) validateAgentConfig(cfg *config.Config) error {
	// Agent needs models for task execution
	if len(cfg.Agent.Models) == 0 {
		return fmt.Errorf("agent requires at least one model")
	}

	// Agent needs specialization
	if cfg.Agent.Specialization == "" {
		return fmt.Errorf("agent specialization is required")
	}

	// Validate max tasks
	if cfg.Agent.MaxTasks <= 0 {
		return fmt.Errorf("agent max_tasks must be greater than 0")
	}

	return nil
}

// validateHAPConfig validates HAP-specific configuration
func (v *ConfigValidator) validateHAPConfig(cfg *config.Config) error {
	// HAP has different requirements than agent
	// Models are optional for HAP (it facilitates human interaction)
	
	// HAP should have role configuration for proper P2P participation
	if cfg.Agent.Role == "" {
		return fmt.Errorf("HAP requires a role for P2P participation")
	}

	return nil
}

// ValidateMultiBinaryDeployment validates that agent and HAP configs are compatible
func ValidateMultiBinaryDeployment(agentConfig, hapConfig *config.Config) error {
	validators := []func(*config.Config, *config.Config) error{
		validateP2PCompatibility,
		validatePortAssignments,
		validateAgentIdentities,
		validateEncryptionKeys,
	}

	for _, validator := range validators {
		if err := validator(agentConfig, hapConfig); err != nil {
			return err
		}
	}
	return nil
}

// validateP2PCompatibility ensures both configs can participate in same P2P mesh
func validateP2PCompatibility(agentConfig, hapConfig *config.Config) error {
	// Check bootstrap peers compatibility for V2 DHT
	if len(agentConfig.V2.DHT.BootstrapPeers) != len(hapConfig.V2.DHT.BootstrapPeers) {
		return fmt.Errorf("bootstrap peers configuration differs between agent and HAP")
	}

	return nil
}

// validatePortAssignments ensures no port conflicts
func validatePortAssignments(agentConfig, hapConfig *config.Config) error {
	// Check UCXI ports if enabled
	if agentConfig.UCXL.Enabled && hapConfig.UCXL.Enabled {
		if agentConfig.UCXL.Server.Port == hapConfig.UCXL.Server.Port {
			return fmt.Errorf("UCXI port conflict: both configs use port %d", agentConfig.UCXL.Server.Port)
		}
	}

	return nil
}

// validateAgentIdentities ensures agent IDs don't conflict
func validateAgentIdentities(agentConfig, hapConfig *config.Config) error {
	if agentConfig.Agent.ID == hapConfig.Agent.ID {
		return fmt.Errorf("agent ID conflict: both configs use ID %s", agentConfig.Agent.ID)
	}

	return nil
}

// validateEncryptionKeys ensures encryption compatibility
func validateEncryptionKeys(agentConfig, hapConfig *config.Config) error {
	// TODO: Implement encryption validation when V2 Security is available
	// Both should use same encryption settings for compatibility
	// if agentConfig.V2.Security.EncryptionEnabled != hapConfig.V2.Security.EncryptionEnabled {
	//	return fmt.Errorf("encryption settings mismatch")
	// }

	return nil
}

// CheckForRunningInstance checks if another instance is already running
func CheckForRunningInstance(agentID string, binaryType BinaryType) error {
	lockFile := fmt.Sprintf("/tmp/bzzz-%s-%s.lock", agentID, binaryType)

	if _, err := os.Stat(lockFile); err == nil {
		return fmt.Errorf("instance already running: %s %s", binaryType, agentID)
	}

	// Create lock file
	return os.WriteFile(lockFile, []byte(fmt.Sprintf("%d", os.Getpid())), 0644)
}

// RemoveInstanceLock removes the instance lock file
func RemoveInstanceLock(agentID string, binaryType BinaryType) error {
	lockFile := fmt.Sprintf("/tmp/bzzz-%s-%s.lock", agentID, binaryType)
	return os.Remove(lockFile)
}

// GetConfigPath determines the configuration file path
func GetConfigPath() string {
	configPath := os.Getenv("BZZZ_CONFIG_PATH")
	if configPath == "" {
		configPath = ".bzzz/config.yaml"
	}
	return configPath
}

// NeedsSetup checks if the system needs to run setup mode
func NeedsSetup() bool {
	configPath := GetConfigPath()
	return config.IsSetupRequired(configPath)
}