package engine

import "math"

// ColorConfig represents the configuration for color generation
type ColorConfig struct {
	// Saturation settings
	ColorSaturation     float64 // Saturation for normal colors [0, 1]
	GrayscaleSaturation float64 // Saturation for grayscale colors [0, 1]
	
	// Lightness ranges
	ColorLightness     LightnessRange // Lightness range for normal colors
	GrayscaleLightness LightnessRange // Lightness range for grayscale colors
	
	// Hue restrictions
	Hues []float64 // Allowed hues in degrees [0, 360] or range [0, 1]. Empty means no restriction
	
	// Background color
	BackColor *Color // Background color (nil for transparent)
	
	// Icon padding
	IconPadding float64 // Padding as percentage of icon size [0, 1]
}

// LightnessRange represents a range of lightness values
type LightnessRange struct {
	Min float64 // Minimum lightness [0, 1]
	Max float64 // Maximum lightness [0, 1]
}

// GetLightness returns a lightness value for the given position in range [0, 1]
// where 0 returns Min and 1 returns Max
func (lr LightnessRange) GetLightness(value float64) float64 {
	// Clamp value to [0, 1] range
	value = clamp(value, 0, 1)
	
	// Linear interpolation between min and max
	result := lr.Min + value*(lr.Max-lr.Min)
	
	// Clamp result to valid lightness range
	return clamp(result, 0, 1)
}

// DefaultColorConfig returns the default configuration matching the JavaScript implementation
func DefaultColorConfig() ColorConfig {
	return ColorConfig{
		ColorSaturation:     0.5,
		GrayscaleSaturation: 0.0,
		ColorLightness:      LightnessRange{Min: 0.4, Max: 0.8},
		GrayscaleLightness:  LightnessRange{Min: 0.3, Max: 0.9},
		Hues:               nil, // No hue restriction
		BackColor:          nil, // Transparent background
		IconPadding:        0.08,
	}
}

// RestrictHue applies hue restrictions to the given hue value
// Returns the restricted hue in range [0, 1]
func (c ColorConfig) RestrictHue(originalHue float64) float64 {
	// Normalize hue to [0, 1) range
	hue := math.Mod(originalHue, 1.0)
	if hue < 0 {
		hue += 1.0
	}
	
	// If no hue restrictions, return original
	if len(c.Hues) == 0 {
		return hue
	}
	
	// Find the closest allowed hue
	// originalHue is in range [0, 1], multiply by 0.999 to get range [0, 1)
	// then truncate to get index
	index := int((0.999 * hue * float64(len(c.Hues))))
	if index >= len(c.Hues) {
		index = len(c.Hues) - 1
	}
	
	restrictedHue := c.Hues[index]
	
	// Convert from degrees to turns in range [0, 1)
	// Handle any turn - e.g. 746° is valid
	result := math.Mod(restrictedHue/360.0, 1.0)
	if result < 0 {
		result += 1.0
	}
	
	return result
}

// ValidateConfig validates and corrects a ColorConfig to ensure all values are within valid ranges
func (c *ColorConfig) Validate() {
	// Clamp saturation values
	c.ColorSaturation = clamp(c.ColorSaturation, 0, 1)
	c.GrayscaleSaturation = clamp(c.GrayscaleSaturation, 0, 1)
	
	// Validate lightness ranges
	c.ColorLightness.Min = clamp(c.ColorLightness.Min, 0, 1)
	c.ColorLightness.Max = clamp(c.ColorLightness.Max, 0, 1)
	if c.ColorLightness.Min > c.ColorLightness.Max {
		c.ColorLightness.Min, c.ColorLightness.Max = c.ColorLightness.Max, c.ColorLightness.Min
	}
	
	c.GrayscaleLightness.Min = clamp(c.GrayscaleLightness.Min, 0, 1)
	c.GrayscaleLightness.Max = clamp(c.GrayscaleLightness.Max, 0, 1)
	if c.GrayscaleLightness.Min > c.GrayscaleLightness.Max {
		c.GrayscaleLightness.Min, c.GrayscaleLightness.Max = c.GrayscaleLightness.Max, c.GrayscaleLightness.Min
	}
	
	// Clamp icon padding
	c.IconPadding = clamp(c.IconPadding, 0, 1)
	
	// Validate hues (no need to clamp as RestrictHue handles normalization)
}

// ColorConfigBuilder provides a fluent interface for building ColorConfig
type ColorConfigBuilder struct {
	config ColorConfig
}

// NewColorConfigBuilder creates a new builder with default values
func NewColorConfigBuilder() *ColorConfigBuilder {
	return &ColorConfigBuilder{
		config: DefaultColorConfig(),
	}
}

// WithColorSaturation sets the color saturation
func (b *ColorConfigBuilder) WithColorSaturation(saturation float64) *ColorConfigBuilder {
	b.config.ColorSaturation = saturation
	return b
}

// WithGrayscaleSaturation sets the grayscale saturation
func (b *ColorConfigBuilder) WithGrayscaleSaturation(saturation float64) *ColorConfigBuilder {
	b.config.GrayscaleSaturation = saturation
	return b
}

// WithColorLightness sets the color lightness range
func (b *ColorConfigBuilder) WithColorLightness(min, max float64) *ColorConfigBuilder {
	b.config.ColorLightness = LightnessRange{Min: min, Max: max}
	return b
}

// WithGrayscaleLightness sets the grayscale lightness range
func (b *ColorConfigBuilder) WithGrayscaleLightness(min, max float64) *ColorConfigBuilder {
	b.config.GrayscaleLightness = LightnessRange{Min: min, Max: max}
	return b
}

// WithHues sets the allowed hues in degrees
func (b *ColorConfigBuilder) WithHues(hues ...float64) *ColorConfigBuilder {
	b.config.Hues = make([]float64, len(hues))
	copy(b.config.Hues, hues)
	return b
}

// WithBackColor sets the background color
func (b *ColorConfigBuilder) WithBackColor(color Color) *ColorConfigBuilder {
	b.config.BackColor = &color
	return b
}

// WithIconPadding sets the icon padding
func (b *ColorConfigBuilder) WithIconPadding(padding float64) *ColorConfigBuilder {
	b.config.IconPadding = padding
	return b
}

// Build returns the configured ColorConfig after validation
func (b *ColorConfigBuilder) Build() ColorConfig {
	b.config.Validate()
	return b.config
}