package region

import (
	"fmt"
	"log"
	"sync"
)

// NewRegionMapRange creates a new region map range for a zone
func NewRegionMapRange(zoneName string) *RegionMapRange {
	return &RegionMapRange{
		name:       zoneName,
		versionMap: make(map[*VersionRange]RegionMap),
	}
}

// AddVersionRange adds a version-specific region map
func (rmr *RegionMapRange) AddVersionRange(minVersion, maxVersion int32, regionMap RegionMap) error {
	rmr.mutex.Lock()
	defer rmr.mutex.Unlock()
	
	if regionMap == nil {
		return fmt.Errorf("region map cannot be nil")
	}
	
	versionRange := &VersionRange{
		MinVersion: minVersion,
		MaxVersion: maxVersion,
	}
	
	rmr.versionMap[versionRange] = regionMap
	
	log.Printf("[Region] Added version range [%d-%d] for zone '%s'", 
		minVersion, maxVersion, rmr.name)
	
	return nil
}

// FindVersionRange finds a region map that supports the given version range
func (rmr *RegionMapRange) FindVersionRange(minVersion, maxVersion int32) (RegionMap, bool) {
	rmr.mutex.RLock()
	defer rmr.mutex.RUnlock()
	
	for versionRange, regionMap := range rmr.versionMap {
		// If min and max version are both in range
		if versionRange.MinVersion <= minVersion && maxVersion <= versionRange.MaxVersion {
			return regionMap, true
		}
		// If the min version is in range, but max range is 0 (unlimited)
		if versionRange.MinVersion <= minVersion && versionRange.MaxVersion == 0 {
			return regionMap, true
		}
		// If min version is 0 and max_version has a cap
		if versionRange.MinVersion == 0 && maxVersion <= versionRange.MaxVersion {
			return regionMap, true
		}
	}
	
	return nil, false
}

// FindRegionByVersion finds a region map for a specific client version
func (rmr *RegionMapRange) FindRegionByVersion(version int32) RegionMap {
	rmr.mutex.RLock()
	defer rmr.mutex.RUnlock()
	
	var fallbackMap RegionMap
	
	for versionRange, regionMap := range rmr.versionMap {
		// If min and max version are both 0, this is a fallback map
		if versionRange.MinVersion == 0 && versionRange.MaxVersion == 0 {
			fallbackMap = regionMap
			continue
		}
		
		// Check if version is in range
		if version >= versionRange.MinVersion {
			// If MaxVersion is 0, it means unlimited
			if versionRange.MaxVersion == 0 || version <= versionRange.MaxVersion {
				return regionMap
			}
		}
	}
	
	// Return fallback map if no specific version match
	return fallbackMap
}

// GetAllVersionRanges returns all version ranges and their associated region maps
func (rmr *RegionMapRange) GetAllVersionRanges() map[*VersionRange]RegionMap {
	rmr.mutex.RLock()
	defer rmr.mutex.RUnlock()
	
	// Return a copy to prevent external modification
	result := make(map[*VersionRange]RegionMap)
	for vr, rm := range rmr.versionMap {
		result[vr] = rm
	}
	
	return result
}

// GetLoadedMapCount returns the number of loaded region maps
func (rmr *RegionMapRange) GetLoadedMapCount() int {
	rmr.mutex.RLock()
	defer rmr.mutex.RUnlock()
	
	return len(rmr.versionMap)
}

// RemoveVersionRange removes a version range by its min/max versions
func (rmr *RegionMapRange) RemoveVersionRange(minVersion, maxVersion int32) bool {
	rmr.mutex.Lock()
	defer rmr.mutex.Unlock()
	
	for versionRange := range rmr.versionMap {
		if versionRange.MinVersion == minVersion && versionRange.MaxVersion == maxVersion {
			delete(rmr.versionMap, versionRange)
			log.Printf("[Region] Removed version range [%d-%d] for zone '%s'", 
				minVersion, maxVersion, rmr.name)
			return true
		}
	}
	
	return false
}

// Clear removes all version ranges and region maps
func (rmr *RegionMapRange) Clear() {
	rmr.mutex.Lock()
	defer rmr.mutex.Unlock()
	
	// Clear the map
	for vr := range rmr.versionMap {
		delete(rmr.versionMap, vr)
	}
	
	log.Printf("[Region] Cleared all version ranges for zone '%s'", rmr.name)
}

// GetName returns the zone name for this region map range
func (rmr *RegionMapRange) GetName() string {
	return rmr.name
}

// GetMinVersion returns the minimum version supported by any region map
func (rmr *RegionMapRange) GetMinVersion() int32 {
	rmr.mutex.RLock()
	defer rmr.mutex.RUnlock()
	
	if len(rmr.versionMap) == 0 {
		return 0
	}
	
	minVersion := int32(999999) // Start with a high value
	
	for versionRange := range rmr.versionMap {
		if versionRange.MinVersion > 0 && versionRange.MinVersion < minVersion {
			minVersion = versionRange.MinVersion
		}
	}
	
	if minVersion == 999999 {
		return 0 // No valid minimum found
	}
	
	return minVersion
}

// GetMaxVersion returns the maximum version supported by any region map
func (rmr *RegionMapRange) GetMaxVersion() int32 {
	rmr.mutex.RLock()
	defer rmr.mutex.RUnlock()
	
	if len(rmr.versionMap) == 0 {
		return 0
	}
	
	maxVersion := int32(0)
	
	for versionRange := range rmr.versionMap {
		if versionRange.MaxVersion > maxVersion {
			maxVersion = versionRange.MaxVersion
		}
	}
	
	return maxVersion
}

// NewVersionRange creates a new version range
func NewVersionRange(minVersion, maxVersion int32) *VersionRange {
	return &VersionRange{
		MinVersion: minVersion,
		MaxVersion: maxVersion,
	}
}

// GetMinVersion returns the minimum version for this range
func (vr *VersionRange) GetMinVersion() int32 {
	return vr.MinVersion
}

// GetMaxVersion returns the maximum version for this range
func (vr *VersionRange) GetMaxVersion() int32 {
	return vr.MaxVersion
}

// ContainsVersion checks if a version is within this range
func (vr *VersionRange) ContainsVersion(version int32) bool {
	if vr.MinVersion > 0 && version < vr.MinVersion {
		return false
	}
	
	if vr.MaxVersion > 0 && version > vr.MaxVersion {
		return false
	}
	
	return true
}

// String returns a string representation of the version range
func (vr *VersionRange) String() string {
	if vr.MaxVersion == 0 {
		return fmt.Sprintf("[%d+]", vr.MinVersion)
	}
	return fmt.Sprintf("[%d-%d]", vr.MinVersion, vr.MaxVersion)
}