package context

import (
	"fmt"
	"time"

	"chorus.services/bzzz/pkg/ucxl"
	"chorus.services/bzzz/pkg/config"
)

// ContextNode represents a hierarchical context node in the SLURP system.
//
// Context nodes form a tree structure where child nodes inherit and
// override properties from their parents. This enables efficient
// cascading context resolution with bounded depth traversal.
type ContextNode struct {
	// Identity and addressing
	Path        string       `json:"path"`         // Filesystem path
	UCXLAddress ucxl.Address `json:"ucxl_address"` // Associated UCXL address
	Summary     string       `json:"summary"`      // Brief description
	Purpose     string       `json:"purpose"`      // What this component does
	
	// Context metadata
	Technologies []string `json:"technologies"` // Technologies used
	Tags         []string `json:"tags"`         // Categorization tags
	Insights     []string `json:"insights"`     // Analytical insights
	
	// Hierarchy control
	OverridesParent    bool `json:"overrides_parent"`     // Whether this overrides parent context
	ContextSpecificity int  `json:"context_specificity"`  // Specificity level (higher = more specific)
	AppliesToChildren  bool `json:"applies_to_children"`  // Whether this applies to child directories
	
	// Metadata
	GeneratedAt   time.Time `json:"generated_at"`   // When context was generated
	RAGConfidence float64   `json:"rag_confidence"` // RAG system confidence (0-1)
	
	// Access control
	EncryptedFor []string                   `json:"encrypted_for"` // Roles that can access
	AccessLevel  RoleAccessLevel    `json:"access_level"`  // Required access level
	
	// Custom metadata
	Metadata map[string]interface{} `json:"metadata,omitempty"` // Additional metadata
}

// RoleAccessLevel defines encryption levels for different roles
// This mirrors the config.AuthorityLevel but adds more granular access control
type RoleAccessLevel int

const (
	AccessPublic RoleAccessLevel = iota // Anyone can access
	AccessLow                           // Basic role access
	AccessMedium                        // Coordination role access
	AccessHigh                          // Decision role access
	AccessCritical                      // Master role access only
)

// EncryptedContext represents role-encrypted context data for DHT storage
type EncryptedContext struct {
	UCXLAddress    ucxl.Address    `json:"ucxl_address"`    // Associated UCXL address
	Role           string          `json:"role"`            // Target role for access
	AccessLevel    RoleAccessLevel `json:"access_level"`    // Required access level
	EncryptedData  []byte          `json:"encrypted_data"`  // Encrypted context data
	KeyFingerprint string          `json:"key_fingerprint"` // Key identification
	CreatedAt      time.Time       `json:"created_at"`      // When encrypted
}

// ResolvedContext represents the final resolved context output
//
// This is the primary output of the context resolution process, combining
// information from multiple hierarchy levels and applying global contexts.
type ResolvedContext struct {
	UCXLAddress  ucxl.Address `json:"ucxl_address"` // Original UCXL address
	Summary      string       `json:"summary"`      // Resolved summary
	Purpose      string       `json:"purpose"`      // Resolved purpose
	Technologies []string     `json:"technologies"` // Merged technologies
	Tags         []string     `json:"tags"`         // Merged tags
	Insights     []string     `json:"insights"`     // Merged insights
	
	// Resolution metadata
	ContextSourcePath        string    `json:"context_source_path"`         // Primary source context path
	InheritanceChain         []string  `json:"inheritance_chain"`           // Context inheritance chain
	ResolutionConfidence     float64   `json:"resolution_confidence"`       // Overall confidence (0-1)
	BoundedDepth            int       `json:"bounded_depth"`               // Actual traversal depth used
	GlobalContextsApplied   bool      `json:"global_contexts_applied"`     // Whether global contexts were applied
	ResolvedAt              time.Time `json:"resolved_at"`                 // When resolution occurred
}

// ResolutionStatistics represents statistics about context resolution operations
type ResolutionStatistics struct {
	ContextNodes      int           `json:"context_nodes"`       // Total context nodes in hierarchy
	GlobalContexts    int           `json:"global_contexts"`     // Number of global contexts
	MaxHierarchyDepth int           `json:"max_hierarchy_depth"` // Maximum hierarchy depth allowed
	CachedResolutions int           `json:"cached_resolutions"`  // Number of cached resolutions
	TotalResolutions  int           `json:"total_resolutions"`   // Total resolution operations
	AverageDepth      float64       `json:"average_depth"`       // Average traversal depth
	CacheHitRate      float64       `json:"cache_hit_rate"`      // Cache hit rate (0-1)
	LastResetAt       time.Time     `json:"last_reset_at"`       // When stats were last reset
}

// ContextScope defines the scope of a context node's application
type ContextScope string

const (
	ScopeLocal    ContextScope = "local"    // Only applies to this specific file/directory
	ScopeChildren ContextScope = "children" // Applies to this and all child directories
	ScopeGlobal   ContextScope = "global"   // Applies to the entire project
)

// HierarchyStats represents statistics about hierarchy operations
type HierarchyStats struct {
	NodesCreated      int           `json:"nodes_created"`       // Number of nodes created
	NodesUpdated      int           `json:"nodes_updated"`       // Number of nodes updated
	FilesAnalyzed     int           `json:"files_analyzed"`      // Number of files analyzed
	DirectoriesScanned int          `json:"directories_scanned"` // Number of directories scanned
	GenerationTime    time.Duration `json:"generation_time"`     // Time taken for generation
	AverageConfidence float64       `json:"average_confidence"`  // Average confidence score
	TotalSize         int64         `json:"total_size"`          // Total size of analyzed content
	SkippedFiles      int           `json:"skipped_files"`       // Number of files skipped
	Errors            []string      `json:"errors"`              // Generation errors
}

// CacheEntry represents a cached context resolution
type CacheEntry struct {
	Key           string           `json:"key"`            // Cache key
	ResolvedCtx   *ResolvedContext `json:"resolved_ctx"`   // Cached resolved context
	CreatedAt     time.Time        `json:"created_at"`     // When cached
	ExpiresAt     time.Time        `json:"expires_at"`     // When cache expires
	AccessCount   int              `json:"access_count"`   // Number of times accessed
	LastAccessed  time.Time        `json:"last_accessed"`  // When last accessed
}

// ValidationResult represents the result of context validation
type ValidationResult struct {
	Valid           bool               `json:"valid"`            // Whether context is valid
	ConfidenceScore float64            `json:"confidence_score"` // Overall confidence (0-1)
	QualityScore    float64            `json:"quality_score"`    // Quality assessment (0-1)
	Issues          []*ValidationIssue `json:"issues"`           // Validation issues found
	ValidatedAt     time.Time          `json:"validated_at"`     // When validation occurred
	ValidatedBy     string             `json:"validated_by"`     // Who/what performed validation
}

// ValidationIssue represents an issue found during validation
type ValidationIssue struct {
	Severity   string `json:"severity"`   // error, warning, info
	Message    string `json:"message"`    // Issue description
	Field      string `json:"field"`      // Affected field
	Suggestion string `json:"suggestion"` // How to fix
}

// MergeOptions defines options for merging contexts during resolution
type MergeOptions struct {
	PreferParent          bool     `json:"prefer_parent"`           // Prefer parent values over child
	MergeTechnologies     bool     `json:"merge_technologies"`      // Merge technology lists
	MergeTags             bool     `json:"merge_tags"`              // Merge tag lists
	MergeInsights         bool     `json:"merge_insights"`          // Merge insight lists
	ExcludedFields        []string `json:"excluded_fields"`         // Fields to exclude from merge
	WeightParentByDepth   bool     `json:"weight_parent_by_depth"`  // Weight parent influence by depth
	MinConfidenceThreshold float64 `json:"min_confidence_threshold"` // Minimum confidence to include
}

// BatchResolutionRequest represents a batch resolution request
type BatchResolutionRequest struct {
	Addresses []ucxl.Address `json:"addresses"` // UCXL addresses to resolve
	MaxDepth  int            `json:"max_depth"` // Maximum traversal depth
	Role      string         `json:"role"`      // Requesting role for access control
	Options   *MergeOptions  `json:"options"`   // Merge options
}

// BatchResolutionResult represents the result of batch resolution
type BatchResolutionResult struct {
	Results     map[string]*ResolvedContext `json:"results"`      // Resolution results by address
	Errors      map[string]error            `json:"errors"`       // Errors by address
	ProcessedAt time.Time                   `json:"processed_at"` // When batch was processed
	Duration    time.Duration               `json:"duration"`     // Total processing time
	CacheHits   int                         `json:"cache_hits"`   // Number of cache hits
	CacheMisses int                         `json:"cache_misses"` // Number of cache misses
}

// ContextError represents a context-related error with structured information
type ContextError struct {
	Type        string            `json:"type"`         // Error type (validation, resolution, access, etc.)
	Message     string            `json:"message"`      // Human-readable error message
	Code        string            `json:"code"`         // Machine-readable error code
	Address     *ucxl.Address     `json:"address"`      // Related UCXL address if applicable
	Context     map[string]string `json:"context"`      // Additional context information
	Underlying  error             `json:"underlying"`   // Underlying error if any
}

func (e *ContextError) Error() string {
	if e.Address != nil {
		return fmt.Sprintf("context error [%s:%s] for address %s: %s", e.Type, e.Code, e.Address.String(), e.Message)
	}
	return fmt.Sprintf("context error [%s:%s]: %s", e.Type, e.Code, e.Message)
}

func (e *ContextError) Unwrap() error {
	return e.Underlying
}

// Common error types and codes
const (
	ErrorTypeValidation     = "validation"
	ErrorTypeResolution     = "resolution" 
	ErrorTypeAccess         = "access"
	ErrorTypeStorage        = "storage"
	ErrorTypeEncryption     = "encryption"
	ErrorTypeDHT            = "dht"
	ErrorTypeHierarchy      = "hierarchy"
	ErrorTypeCache          = "cache"
	ErrorTypeTemporalGraph  = "temporal_graph"
	ErrorTypeIntelligence   = "intelligence"
)

const (
	ErrorCodeInvalidAddress    = "invalid_address"
	ErrorCodeInvalidContext    = "invalid_context"
	ErrorCodeInvalidRole       = "invalid_role"
	ErrorCodeAccessDenied      = "access_denied"
	ErrorCodeNotFound          = "not_found"
	ErrorCodeDepthExceeded     = "depth_exceeded"
	ErrorCodeCycleDetected     = "cycle_detected"
	ErrorCodeEncryptionFailed  = "encryption_failed"
	ErrorCodeDecryptionFailed  = "decryption_failed"
	ErrorCodeDHTError          = "dht_error"
	ErrorCodeCacheError        = "cache_error"
	ErrorCodeStorageError      = "storage_error"
	ErrorCodeInvalidConfig     = "invalid_config"
	ErrorCodeTimeout           = "timeout"
	ErrorCodeInternalError     = "internal_error"
)

// NewContextError creates a new context error with structured information
func NewContextError(errorType, code, message string) *ContextError {
	return &ContextError{
		Type:    errorType,
		Code:    code,
		Message: message,
		Context: make(map[string]string),
	}
}

// WithAddress adds an address to the error context
func (e *ContextError) WithAddress(address ucxl.Address) *ContextError {
	e.Address = &address
	return e
}

// WithContext adds contextual information to the error
func (e *ContextError) WithContext(key, value string) *ContextError {
	if e.Context == nil {
		e.Context = make(map[string]string)
	}
	e.Context[key] = value
	return e
}

// WithUnderlying wraps an underlying error
func (e *ContextError) WithUnderlying(err error) *ContextError {
	e.Underlying = err
	return e
}

// String returns the string representation of the access level
func (ral RoleAccessLevel) String() string {
	switch ral {
	case AccessPublic:
		return "public"
	case AccessLow:
		return "low"
	case AccessMedium:
		return "medium"
	case AccessHigh:
		return "high"
	case AccessCritical:
		return "critical"
	default:
		return "unknown"
	}
}

// ParseRoleAccessLevel parses a string into a RoleAccessLevel
func ParseRoleAccessLevel(level string) (RoleAccessLevel, error) {
	switch level {
	case "public":
		return AccessPublic, nil
	case "low":
		return AccessLow, nil
	case "medium":
		return AccessMedium, nil
	case "high":
		return AccessHigh, nil
	case "critical":
		return AccessCritical, nil
	default:
		return AccessPublic, NewContextError(ErrorTypeValidation, ErrorCodeInvalidRole, 
			fmt.Sprintf("invalid role access level: %s", level))
	}
}

// AuthorityToAccessLevel converts config.AuthorityLevel to RoleAccessLevel
func AuthorityToAccessLevel(authority config.AuthorityLevel) RoleAccessLevel {
	switch authority {
	case config.AuthorityMaster:
		return AccessCritical
	case config.AuthorityDecision:
		return AccessHigh
	case config.AuthorityCoordination:
		return AccessMedium
	case config.AuthoritySuggestion:
		return AccessLow
	case config.AuthorityReadOnly:
		return AccessPublic
	default:
		return AccessPublic
	}
}

// Validate validates a ContextNode for consistency and completeness
func (cn *ContextNode) Validate() error {
	if cn.Path == "" {
		return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "context path cannot be empty")
	}

	if err := cn.UCXLAddress.Validate(); err != nil {
		return NewContextError(ErrorTypeValidation, ErrorCodeInvalidAddress, 
			"invalid UCXL address").WithUnderlying(err).WithAddress(cn.UCXLAddress)
	}

	if cn.Summary == "" {
		return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, 
			"context summary cannot be empty").WithAddress(cn.UCXLAddress)
	}

	if cn.RAGConfidence < 0 || cn.RAGConfidence > 1 {
		return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, 
			"RAG confidence must be between 0 and 1").WithAddress(cn.UCXLAddress).
			WithContext("confidence", fmt.Sprintf("%.2f", cn.RAGConfidence))
	}

	if cn.ContextSpecificity < 0 {
		return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, 
			"context specificity cannot be negative").WithAddress(cn.UCXLAddress).
			WithContext("specificity", fmt.Sprintf("%d", cn.ContextSpecificity))
	}

	// Validate role access levels
	for _, role := range cn.EncryptedFor {
		if role == "" {
			return NewContextError(ErrorTypeValidation, ErrorCodeInvalidRole, 
				"encrypted_for roles cannot be empty").WithAddress(cn.UCXLAddress)
		}
	}

	return nil
}

// Validate validates a ResolvedContext for consistency and completeness  
func (rc *ResolvedContext) Validate() error {
	if err := rc.UCXLAddress.Validate(); err != nil {
		return NewContextError(ErrorTypeValidation, ErrorCodeInvalidAddress, 
			"invalid UCXL address in resolved context").WithUnderlying(err).WithAddress(rc.UCXLAddress)
	}

	if rc.Summary == "" {
		return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, 
			"resolved context summary cannot be empty").WithAddress(rc.UCXLAddress)
	}

	if rc.ResolutionConfidence < 0 || rc.ResolutionConfidence > 1 {
		return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, 
			"resolution confidence must be between 0 and 1").WithAddress(rc.UCXLAddress).
			WithContext("confidence", fmt.Sprintf("%.2f", rc.ResolutionConfidence))
	}

	if rc.BoundedDepth < 0 {
		return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, 
			"bounded depth cannot be negative").WithAddress(rc.UCXLAddress).
			WithContext("depth", fmt.Sprintf("%d", rc.BoundedDepth))
	}

	if rc.ContextSourcePath == "" {
		return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, 
			"context source path cannot be empty").WithAddress(rc.UCXLAddress)
	}

	return nil
}

// HasRole checks if the context node is encrypted for a specific role
func (cn *ContextNode) HasRole(role string) bool {
	for _, r := range cn.EncryptedFor {
		if r == role || r == "*" {
			return true
		}
	}
	return false
}

// CanAccess checks if a role can access this context based on authority level
func (cn *ContextNode) CanAccess(role string, authority config.AuthorityLevel) bool {
	// Master authority can access everything
	if authority == config.AuthorityMaster {
		return true
	}

	// Check if role is explicitly allowed
	if cn.HasRole(role) {
		return true
	}

	// Check access level compatibility
	requiredLevel := AuthorityToAccessLevel(authority)
	return requiredLevel >= cn.AccessLevel
}

// Clone creates a deep copy of the ContextNode
func (cn *ContextNode) Clone() *ContextNode {
	cloned := &ContextNode{
		Path:               cn.Path,
		UCXLAddress:        *cn.UCXLAddress.Clone(),
		Summary:            cn.Summary,
		Purpose:            cn.Purpose,
		Technologies:       make([]string, len(cn.Technologies)),
		Tags:              make([]string, len(cn.Tags)),
		Insights:          make([]string, len(cn.Insights)),
		OverridesParent:   cn.OverridesParent,
		ContextSpecificity: cn.ContextSpecificity,
		AppliesToChildren: cn.AppliesToChildren,
		GeneratedAt:       cn.GeneratedAt,
		RAGConfidence:     cn.RAGConfidence,
		EncryptedFor:      make([]string, len(cn.EncryptedFor)),
		AccessLevel:       cn.AccessLevel,
		Metadata:          make(map[string]interface{}),
	}

	copy(cloned.Technologies, cn.Technologies)
	copy(cloned.Tags, cn.Tags)
	copy(cloned.Insights, cn.Insights)
	copy(cloned.EncryptedFor, cn.EncryptedFor)

	for k, v := range cn.Metadata {
		cloned.Metadata[k] = v
	}

	return cloned
}

// Clone creates a deep copy of the ResolvedContext
func (rc *ResolvedContext) Clone() *ResolvedContext {
	cloned := &ResolvedContext{
		UCXLAddress:              *rc.UCXLAddress.Clone(),
		Summary:                  rc.Summary,
		Purpose:                  rc.Purpose,
		Technologies:             make([]string, len(rc.Technologies)),
		Tags:                     make([]string, len(rc.Tags)),
		Insights:                 make([]string, len(rc.Insights)),
		ContextSourcePath:        rc.ContextSourcePath,
		InheritanceChain:         make([]string, len(rc.InheritanceChain)),
		ResolutionConfidence:     rc.ResolutionConfidence,
		BoundedDepth:            rc.BoundedDepth,
		GlobalContextsApplied:   rc.GlobalContextsApplied,
		ResolvedAt:              rc.ResolvedAt,
	}

	copy(cloned.Technologies, rc.Technologies)
	copy(cloned.Tags, rc.Tags)
	copy(cloned.Insights, rc.Insights)
	copy(cloned.InheritanceChain, rc.InheritanceChain)

	return cloned
}