package ucxl

import (
	"fmt"
	"time"
)

// TemporalNavigator handles temporal navigation operations within UCXL addresses
type TemporalNavigator struct {
	// Navigation history for tracking traversal paths
	history []NavigationStep
	
	// Current position in version space
	currentVersion int
	maxVersion     int
	
	// Version metadata
	versions map[int]VersionInfo
}

// NavigationStep represents a single step in temporal navigation history
type NavigationStep struct {
	FromVersion int           `json:"from_version"`
	ToVersion   int           `json:"to_version"`
	Operation   string        `json:"operation"`
	Timestamp   time.Time     `json:"timestamp"`
	Success     bool          `json:"success"`
	Error       string        `json:"error,omitempty"`
}

// VersionInfo contains metadata about a specific version
type VersionInfo struct {
	Version     int       `json:"version"`
	Created     time.Time `json:"created"`
	Author      string    `json:"author,omitempty"`
	Description string    `json:"description,omitempty"`
	Tags        []string  `json:"tags,omitempty"`
}

// NavigationResult represents the result of a temporal navigation operation
type NavigationResult struct {
	Success        bool         `json:"success"`
	TargetVersion  int          `json:"target_version"`
	PreviousVersion int         `json:"previous_version"`
	VersionInfo    *VersionInfo `json:"version_info,omitempty"`
	Error          string       `json:"error,omitempty"`
}

// TemporalConstraintError represents an error when temporal constraints are violated
type TemporalConstraintError struct {
	Operation     string `json:"operation"`
	RequestedStep int    `json:"requested_step"`
	CurrentVersion int   `json:"current_version"`
	MaxVersion    int    `json:"max_version"`
	Message       string `json:"message"`
}

func (e TemporalConstraintError) Error() string {
	return fmt.Sprintf("temporal constraint violation: %s (current: %d, max: %d, requested: %d)",
		e.Message, e.CurrentVersion, e.MaxVersion, e.RequestedStep)
}

// NewTemporalNavigator creates a new temporal navigator
func NewTemporalNavigator(maxVersion int) *TemporalNavigator {
	if maxVersion < 0 {
		maxVersion = 0
	}

	return &TemporalNavigator{
		history:        make([]NavigationStep, 0),
		currentVersion: maxVersion, // Start at latest version
		maxVersion:     maxVersion,
		versions:       make(map[int]VersionInfo),
	}
}

// Navigate performs temporal navigation based on the temporal segment
func (tn *TemporalNavigator) Navigate(segment TemporalSegment) (*NavigationResult, error) {
	previousVersion := tn.currentVersion
	var targetVersion int
	var err error

	step := NavigationStep{
		FromVersion: previousVersion,
		Timestamp:   time.Now(),
		Operation:   segment.String(),
	}

	switch segment.Type {
	case TemporalLatest:
		targetVersion = tn.maxVersion
		err = tn.navigateToVersion(targetVersion)

	case TemporalAny:
		// For "any", we stay at current version (no navigation)
		targetVersion = tn.currentVersion

	case TemporalSpecific:
		targetVersion = segment.Count
		err = tn.navigateToVersion(targetVersion)

	case TemporalRelative:
		targetVersion, err = tn.navigateRelative(segment.Direction, segment.Count)

	default:
		err = fmt.Errorf("unknown temporal type: %v", segment.Type)
	}

	// Record the navigation step
	step.ToVersion = targetVersion
	step.Success = err == nil
	if err != nil {
		step.Error = err.Error()
	}
	tn.history = append(tn.history, step)

	result := &NavigationResult{
		Success:         err == nil,
		TargetVersion:   targetVersion,
		PreviousVersion: previousVersion,
	}

	// Include version info if available
	if versionInfo, exists := tn.versions[targetVersion]; exists {
		result.VersionInfo = &versionInfo
	}

	if err != nil {
		result.Error = err.Error()
	}

	return result, err
}

// navigateToVersion navigates directly to a specific version
func (tn *TemporalNavigator) navigateToVersion(version int) error {
	if version < 0 {
		return &TemporalConstraintError{
			Operation:      "navigate_to_version",
			RequestedStep:  version,
			CurrentVersion: tn.currentVersion,
			MaxVersion:     tn.maxVersion,
			Message:        "cannot navigate to negative version",
		}
	}

	if version > tn.maxVersion {
		return &TemporalConstraintError{
			Operation:      "navigate_to_version",
			RequestedStep:  version,
			CurrentVersion: tn.currentVersion,
			MaxVersion:     tn.maxVersion,
			Message:        "cannot navigate beyond latest version",
		}
	}

	tn.currentVersion = version
	return nil
}

// navigateRelative performs relative navigation (forward/backward)
func (tn *TemporalNavigator) navigateRelative(direction Direction, count int) (int, error) {
	if count < 0 {
		return tn.currentVersion, &TemporalConstraintError{
			Operation:      fmt.Sprintf("navigate_relative_%s", direction),
			RequestedStep:  count,
			CurrentVersion: tn.currentVersion,
			MaxVersion:     tn.maxVersion,
			Message:        "navigation count cannot be negative",
		}
	}

	var targetVersion int

	switch direction {
	case DirectionBackward:
		targetVersion = tn.currentVersion - count
		if targetVersion < 0 {
			return tn.currentVersion, &TemporalConstraintError{
				Operation:      "navigate_backward",
				RequestedStep:  count,
				CurrentVersion: tn.currentVersion,
				MaxVersion:     tn.maxVersion,
				Message:        "cannot navigate before first version (version 0)",
			}
		}

	case DirectionForward:
		targetVersion = tn.currentVersion + count
		if targetVersion > tn.maxVersion {
			return tn.currentVersion, &TemporalConstraintError{
				Operation:      "navigate_forward",
				RequestedStep:  count,
				CurrentVersion: tn.currentVersion,
				MaxVersion:     tn.maxVersion,
				Message:        "cannot navigate beyond latest version",
			}
		}

	default:
		return tn.currentVersion, fmt.Errorf("unknown navigation direction: %v", direction)
	}

	tn.currentVersion = targetVersion
	return targetVersion, nil
}

// GetCurrentVersion returns the current version position
func (tn *TemporalNavigator) GetCurrentVersion() int {
	return tn.currentVersion
}

// GetMaxVersion returns the maximum available version
func (tn *TemporalNavigator) GetMaxVersion() int {
	return tn.maxVersion
}

// SetMaxVersion updates the maximum version (e.g., when new versions are created)
func (tn *TemporalNavigator) SetMaxVersion(maxVersion int) error {
	if maxVersion < 0 {
		return fmt.Errorf("max version cannot be negative")
	}
	
	tn.maxVersion = maxVersion
	
	// If current version is now beyond max, adjust it
	if tn.currentVersion > tn.maxVersion {
		tn.currentVersion = tn.maxVersion
	}
	
	return nil
}

// GetHistory returns the navigation history
func (tn *TemporalNavigator) GetHistory() []NavigationStep {
	// Return a copy to prevent modification
	history := make([]NavigationStep, len(tn.history))
	copy(history, tn.history)
	return history
}

// ClearHistory clears the navigation history
func (tn *TemporalNavigator) ClearHistory() {
	tn.history = make([]NavigationStep, 0)
}

// GetLastNavigation returns the most recent navigation step
func (tn *TemporalNavigator) GetLastNavigation() *NavigationStep {
	if len(tn.history) == 0 {
		return nil
	}
	
	last := tn.history[len(tn.history)-1]
	return &last
}

// SetVersionInfo sets metadata for a specific version
func (tn *TemporalNavigator) SetVersionInfo(version int, info VersionInfo) {
	info.Version = version // Ensure consistency
	tn.versions[version] = info
}

// GetVersionInfo retrieves metadata for a specific version
func (tn *TemporalNavigator) GetVersionInfo(version int) (*VersionInfo, bool) {
	info, exists := tn.versions[version]
	if exists {
		return &info, true
	}
	return nil, false
}

// GetAllVersions returns metadata for all known versions
func (tn *TemporalNavigator) GetAllVersions() map[int]VersionInfo {
	// Return a copy to prevent modification
	result := make(map[int]VersionInfo)
	for k, v := range tn.versions {
		result[k] = v
	}
	return result
}

// CanNavigateBackward returns true if backward navigation is possible
func (tn *TemporalNavigator) CanNavigateBackward(count int) bool {
	return tn.currentVersion-count >= 0
}

// CanNavigateForward returns true if forward navigation is possible
func (tn *TemporalNavigator) CanNavigateForward(count int) bool {
	return tn.currentVersion+count <= tn.maxVersion
}

// Reset resets the navigator to the latest version and clears history
func (tn *TemporalNavigator) Reset() {
	tn.currentVersion = tn.maxVersion
	tn.ClearHistory()
}

// Clone creates a copy of the temporal navigator
func (tn *TemporalNavigator) Clone() *TemporalNavigator {
	clone := &TemporalNavigator{
		currentVersion: tn.currentVersion,
		maxVersion:     tn.maxVersion,
		history:        make([]NavigationStep, len(tn.history)),
		versions:       make(map[int]VersionInfo),
	}

	// Copy history
	copy(clone.history, tn.history)

	// Copy version info
	for k, v := range tn.versions {
		clone.versions[k] = v
	}

	return clone
}

// ValidateTemporalSegment validates a temporal segment against current navigator state
func (tn *TemporalNavigator) ValidateTemporalSegment(segment TemporalSegment) error {
	switch segment.Type {
	case TemporalLatest:
		// Always valid
		return nil

	case TemporalAny:
		// Always valid
		return nil

	case TemporalSpecific:
		if segment.Count < 0 || segment.Count > tn.maxVersion {
			return &TemporalConstraintError{
				Operation:      "validate_specific",
				RequestedStep:  segment.Count,
				CurrentVersion: tn.currentVersion,
				MaxVersion:     tn.maxVersion,
				Message:        "specific version out of valid range",
			}
		}

	case TemporalRelative:
		if segment.Count < 0 {
			return fmt.Errorf("relative navigation count cannot be negative")
		}

		switch segment.Direction {
		case DirectionBackward:
			if !tn.CanNavigateBackward(segment.Count) {
				return &TemporalConstraintError{
					Operation:      "validate_backward",
					RequestedStep:  segment.Count,
					CurrentVersion: tn.currentVersion,
					MaxVersion:     tn.maxVersion,
					Message:        "backward navigation would go before first version",
				}
			}

		case DirectionForward:
			if !tn.CanNavigateForward(segment.Count) {
				return &TemporalConstraintError{
					Operation:      "validate_forward",
					RequestedStep:  segment.Count,
					CurrentVersion: tn.currentVersion,
					MaxVersion:     tn.maxVersion,
					Message:        "forward navigation would go beyond latest version",
				}
			}

		default:
			return fmt.Errorf("unknown temporal direction: %v", segment.Direction)
		}

	default:
		return fmt.Errorf("unknown temporal type: %v", segment.Type)
	}

	return nil
}