package ucxl

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

// Address represents a parsed UCXL address
// Format: ucxl://agent:role@project:task/temporal_segment/path
type Address struct {
	// Core components
	Agent   string `json:"agent"`
	Role    string `json:"role"`
	Project string `json:"project"`
	Task    string `json:"task"`
	
	// Temporal component
	TemporalSegment TemporalSegment `json:"temporal_segment"`
	
	// Path component
	Path string `json:"path"`
	
	// Original raw address for reference
	Raw string `json:"raw"`
}

// TemporalSegment represents temporal navigation information
type TemporalSegment struct {
	Type      TemporalType `json:"type"`
	Direction Direction    `json:"direction,omitempty"`
	Count     int          `json:"count,omitempty"`
}

// TemporalType defines the type of temporal navigation
type TemporalType string

const (
	TemporalLatest   TemporalType = "latest"   // *^
	TemporalAny      TemporalType = "any"      // *~
	TemporalSpecific TemporalType = "specific" // *~N
	TemporalRelative TemporalType = "relative" // ~~N, ^^N
)

// Direction defines temporal navigation direction
type Direction string

const (
	DirectionBackward Direction = "backward" // ~~
	DirectionForward  Direction = "forward"  // ^^
)

// ValidationError represents an address validation error
type ValidationError struct {
	Field   string
	Message string
	Raw     string
}

func (e ValidationError) Error() string {
	return fmt.Sprintf("UCXL address validation error in %s: %s (address: %s)", e.Field, e.Message, e.Raw)
}

// Regular expressions for validation
var (
	// Component validation patterns
	componentPattern = regexp.MustCompile(`^[a-zA-Z0-9_\-]+$|^any$`)
	pathPattern      = regexp.MustCompile(`^[a-zA-Z0-9_\-/\.]*$`)
	
	// Temporal segment patterns
	temporalLatestPattern   = regexp.MustCompile(`^\*\^$`)                    // *^
	temporalAnyPattern      = regexp.MustCompile(`^\*~$`)                     // *~
	temporalSpecificPattern = regexp.MustCompile(`^\*~(\d+)$`)                // *~N
	temporalBackwardPattern = regexp.MustCompile(`^~~(\d+)$`)                 // ~~N
	temporalForwardPattern  = regexp.MustCompile(`^\^\^(\d+)$`)               // ^^N
	
	// Full address pattern for initial validation
	ucxlAddressPattern = regexp.MustCompile(`^ucxl://([^:]+):([^@]+)@([^:]+):([^/]+)/([^/]+)/?(.*)$`)
)

// Parse parses a UCXL address string into an Address struct
func Parse(address string) (*Address, error) {
	if address == "" {
		return nil, &ValidationError{
			Field:   "address",
			Message: "address cannot be empty",
			Raw:     address,
		}
	}

	// Normalize the address (trim whitespace, convert to lowercase for scheme)
	normalized := strings.TrimSpace(address)
	if !strings.HasPrefix(strings.ToLower(normalized), "ucxl://") {
		return nil, &ValidationError{
			Field:   "scheme",
			Message: "address must start with 'ucxl://'",
			Raw:     address,
		}
	}

	// Check scheme manually since our format doesn't follow standard URL format
	if !strings.HasPrefix(strings.ToLower(normalized), "ucxl://") {
		return nil, &ValidationError{
			Field:   "scheme",
			Message: "scheme must be 'ucxl'",
			Raw:     address,
		}
	}

	// Use regex for detailed component extraction
	// Convert to lowercase for scheme but keep original for case-sensitive parts
	normalizedForPattern := strings.ToLower(normalized[:7]) + normalized[7:] // normalize "ucxl://" part
	matches := ucxlAddressPattern.FindStringSubmatch(normalizedForPattern)
	if matches == nil || len(matches) != 7 {
		return nil, &ValidationError{
			Field:   "format",
			Message: "address format must be 'ucxl://agent:role@project:task/temporal_segment/path'",
			Raw:     address,
		}
	}

	addr := &Address{
		Agent:   normalizeComponent(matches[1]),
		Role:    normalizeComponent(matches[2]),
		Project: normalizeComponent(matches[3]),
		Task:    normalizeComponent(matches[4]),
		Path:    matches[6], // Path can be empty
		Raw:     address,
	}

	// Parse temporal segment
	temporalSegment, err := parseTemporalSegment(matches[5])
	if err != nil {
		return nil, &ValidationError{
			Field:   "temporal_segment",
			Message: err.Error(),
			Raw:     address,
		}
	}
	addr.TemporalSegment = *temporalSegment

	// Validate all components
	if err := addr.Validate(); err != nil {
		return nil, err
	}

	return addr, nil
}

// parseTemporalSegment parses the temporal segment component
func parseTemporalSegment(segment string) (*TemporalSegment, error) {
	if segment == "" {
		return nil, fmt.Errorf("temporal segment cannot be empty")
	}

	// Check for latest (*^)
	if temporalLatestPattern.MatchString(segment) {
		return &TemporalSegment{Type: TemporalLatest}, nil
	}

	// Check for any (*~)
	if temporalAnyPattern.MatchString(segment) {
		return &TemporalSegment{Type: TemporalAny}, nil
	}

	// Check for specific version (*~N)
	if matches := temporalSpecificPattern.FindStringSubmatch(segment); matches != nil {
		count, err := strconv.Atoi(matches[1])
		if err != nil {
			return nil, fmt.Errorf("invalid version number in specific temporal segment: %s", matches[1])
		}
		if count < 0 {
			return nil, fmt.Errorf("version number cannot be negative: %d", count)
		}
		return &TemporalSegment{
			Type:  TemporalSpecific,
			Count: count,
		}, nil
	}

	// Check for backward navigation (~~N)
	if matches := temporalBackwardPattern.FindStringSubmatch(segment); matches != nil {
		count, err := strconv.Atoi(matches[1])
		if err != nil {
			return nil, fmt.Errorf("invalid count in backward temporal segment: %s", matches[1])
		}
		if count < 0 {
			return nil, fmt.Errorf("backward count cannot be negative: %d", count)
		}
		return &TemporalSegment{
			Type:      TemporalRelative,
			Direction: DirectionBackward,
			Count:     count,
		}, nil
	}

	// Check for forward navigation (^^N)
	if matches := temporalForwardPattern.FindStringSubmatch(segment); matches != nil {
		count, err := strconv.Atoi(matches[1])
		if err != nil {
			return nil, fmt.Errorf("invalid count in forward temporal segment: %s", matches[1])
		}
		if count < 0 {
			return nil, fmt.Errorf("forward count cannot be negative: %d", count)
		}
		return &TemporalSegment{
			Type:      TemporalRelative,
			Direction: DirectionForward,
			Count:     count,
		}, nil
	}

	return nil, fmt.Errorf("invalid temporal segment format: %s", segment)
}

// normalizeComponent normalizes address components (case-insensitive)
func normalizeComponent(component string) string {
	return strings.ToLower(strings.TrimSpace(component))
}

// Validate validates the Address components according to BNF grammar rules
func (a *Address) Validate() error {
	// Validate agent component
	if err := validateComponent("agent", a.Agent); err != nil {
		return &ValidationError{
			Field:   "agent",
			Message: err.Error(),
			Raw:     a.Raw,
		}
	}

	// Validate role component
	if err := validateComponent("role", a.Role); err != nil {
		return &ValidationError{
			Field:   "role",
			Message: err.Error(),
			Raw:     a.Raw,
		}
	}

	// Validate project component
	if err := validateComponent("project", a.Project); err != nil {
		return &ValidationError{
			Field:   "project",
			Message: err.Error(),
			Raw:     a.Raw,
		}
	}

	// Validate task component
	if err := validateComponent("task", a.Task); err != nil {
		return &ValidationError{
			Field:   "task",
			Message: err.Error(),
			Raw:     a.Raw,
		}
	}

	// Validate path component (can be empty)
	if a.Path != "" && !pathPattern.MatchString(a.Path) {
		return &ValidationError{
			Field:   "path",
			Message: "path can only contain alphanumeric characters, underscores, hyphens, forward slashes, and dots",
			Raw:     a.Raw,
		}
	}

	return nil
}

// validateComponent validates individual address components
func validateComponent(name, component string) error {
	if component == "" {
		return fmt.Errorf("%s cannot be empty", name)
	}

	if !componentPattern.MatchString(component) {
		return fmt.Errorf("%s can only contain alphanumeric characters, underscores, hyphens, or be 'any'", name)
	}

	return nil
}

// String returns the canonical string representation of the address
func (a *Address) String() string {
	temporalStr := a.TemporalSegment.String()
	if a.Path != "" {
		return fmt.Sprintf("ucxl://%s:%s@%s:%s/%s/%s", a.Agent, a.Role, a.Project, a.Task, temporalStr, a.Path)
	}
	return fmt.Sprintf("ucxl://%s:%s@%s:%s/%s", a.Agent, a.Role, a.Project, a.Task, temporalStr)
}

// String returns the string representation of the temporal segment
func (ts *TemporalSegment) String() string {
	switch ts.Type {
	case TemporalLatest:
		return "*^"
	case TemporalAny:
		return "*~"
	case TemporalSpecific:
		return fmt.Sprintf("*~%d", ts.Count)
	case TemporalRelative:
		if ts.Direction == DirectionBackward {
			return fmt.Sprintf("~~%d", ts.Count)
		}
		return fmt.Sprintf("^^%d", ts.Count)
	default:
		return "*^" // Default to latest
	}
}

// IsWildcard returns true if the address uses wildcard patterns
func (a *Address) IsWildcard() bool {
	return a.Agent == "any" || a.Role == "any" || a.Project == "any" || a.Task == "any"
}

// Matches returns true if this address matches the pattern address
// Supports wildcard matching where "any" matches any value
func (a *Address) Matches(pattern *Address) bool {
	if pattern == nil {
		return false
	}

	// Check each component for wildcard or exact match
	if pattern.Agent != "any" && a.Agent != pattern.Agent {
		return false
	}
	if pattern.Role != "any" && a.Role != pattern.Role {
		return false
	}
	if pattern.Project != "any" && a.Project != pattern.Project {
		return false
	}
	if pattern.Task != "any" && a.Task != pattern.Task {
		return false
	}

	// Path matching (if pattern has path, address must match or be subset)
	if pattern.Path != "" {
		if a.Path == "" {
			return false
		}
		// Simple prefix matching for paths
		if !strings.HasPrefix(a.Path, pattern.Path) {
			return false
		}
	}

	return true
}

// Clone creates a deep copy of the address
func (a *Address) Clone() *Address {
	return &Address{
		Agent:           a.Agent,
		Role:            a.Role,
		Project:         a.Project,
		Task:            a.Task,
		TemporalSegment: a.TemporalSegment, // TemporalSegment is a value type, safe to copy
		Path:            a.Path,
		Raw:             a.Raw,
	}
}

// IsValid performs comprehensive validation and returns true if the address is valid
func (a *Address) IsValid() bool {
	return a.Validate() == nil
}