package handler

import (
	"fmt"
	"net"
	"net/mail"
	"strings"
)

// ValidationError represents a validation error with field-level details.
type ValidationError struct {
	Field   string
	Message string
}

// ValidateCommonName validates a certificate common name.
// Accepts hostnames (TLS), IP addresses, and email addresses (S/MIME).
func ValidateCommonName(cn string) error {
	if cn == "" {
		return ValidationError{Field: "common_name", Message: "common_name is required"}
	}
	if len(cn) > 253 {
		return ValidationError{Field: "common_name", Message: "common_name must be 253 characters or fewer"}
	}
	// If CN contains @, validate as email address (S/MIME certificates)
	if strings.Contains(cn, "@") {
		if _, err := mail.ParseAddress(cn); err != nil {
			return ValidationError{Field: "common_name", Message: fmt.Sprintf("invalid email format for S/MIME common name: %v", err)}
		}
		return nil
	}
	// Basic hostname validation: allow alphanumeric, dots, hyphens
	if err := isValidHostname(cn); err != nil {
		return ValidationError{Field: "common_name", Message: fmt.Sprintf("invalid hostname format: %v", err)}
	}
	return nil
}

// ValidateRequired checks if a string field is present and non-empty.
func ValidateRequired(field, value string) error {
	if value == "" {
		return ValidationError{Field: field, Message: fmt.Sprintf("%s is required", field)}
	}
	return nil
}

// ValidateStringLength checks if a string is within acceptable length bounds.
func ValidateStringLength(field, value string, maxLen int) error {
	if len(value) > maxLen {
		return ValidationError{Field: field, Message: fmt.Sprintf("%s must be %d characters or fewer", field, maxLen)}
	}
	return nil
}

// ValidateCSRPEM validates a certificate signing request PEM block.
func ValidateCSRPEM(csrPEM string) error {
	if csrPEM == "" {
		return ValidationError{Field: "csr_pem", Message: "csr_pem is required"}
	}
	if !strings.HasPrefix(strings.TrimSpace(csrPEM), "-----BEGIN CERTIFICATE REQUEST-----") {
		return ValidationError{Field: "csr_pem", Message: "csr_pem must be a valid PEM-encoded certificate request"}
	}
	return nil
}

// ValidatePolicyType checks if a policy rule type is valid.
func ValidatePolicyType(policyType interface{}) error {
	validTypes := map[string]bool{
		"AllowedIssuers":      true,
		"AllowedDomains":      true,
		"RequiredMetadata":    true,
		"AllowedEnvironments": true,
		"RenewalLeadTime":     true,
		"CertificateLifetime": true,
	}
	typeStr := fmt.Sprintf("%v", policyType)
	if !validTypes[typeStr] {
		return ValidationError{Field: "type", Message: "type must be one of: AllowedIssuers, AllowedDomains, RequiredMetadata, AllowedEnvironments, RenewalLeadTime, CertificateLifetime"}
	}
	return nil
}

// ValidatePolicySeverity checks if a severity level is valid.
func ValidatePolicySeverity(severity interface{}) error {
	validSeverities := map[string]bool{
		"Warning":  true,
		"Error":    true,
		"Critical": true,
	}
	sevStr := fmt.Sprintf("%v", severity)
	if !validSeverities[sevStr] {
		return ValidationError{Field: "severity", Message: "severity must be one of: Warning, Error, Critical"}
	}
	return nil
}

// isValidHostname performs basic validation on a hostname.
func isValidHostname(hostname string) error {
	// Use net.SplitHostPort-compatible check
	// Hostname can be an IP or domain name
	if ip := net.ParseIP(hostname); ip != nil {
		return nil // Valid IP address
	}

	// For domain names, check basic format
	if len(hostname) == 0 || len(hostname) > 253 {
		return fmt.Errorf("hostname length invalid")
	}

	// Check for invalid characters (very basic)
	for _, char := range hostname {
		if !isValidHostnameChar(char) {
			return fmt.Errorf("hostname contains invalid character: %c", char)
		}
	}

	// Labels must not start or end with hyphen
	labels := strings.Split(hostname, ".")
	for _, label := range labels {
		if len(label) == 0 {
			return fmt.Errorf("hostname has empty label")
		}
		if strings.HasPrefix(label, "-") || strings.HasSuffix(label, "-") {
			return fmt.Errorf("hostname labels cannot start or end with hyphen")
		}
	}

	return nil
}

// isValidHostnameChar checks if a character is valid in a hostname.
func isValidHostnameChar(r rune) bool {
	return (r >= 'a' && r <= 'z') ||
		(r >= 'A' && r <= 'Z') ||
		(r >= '0' && r <= '9') ||
		r == '.' ||
		r == '-' ||
		r == '_' || // Underscores are sometimes allowed
		r == '*' // Wildcard support
}

// Error method makes ValidationError satisfy the error interface.
func (e ValidationError) Error() string {
	return e.Message
}
