package discovery

import (
	"time"
)

// ServiceStatus represents the health of an individual service on a node.
type ServiceStatus struct {
	Name    string `json:"name"`              // e.g. "rqlite", "gateway", "olric"
	Running bool   `json:"running"`           // whether the process is up
	Healthy bool   `json:"healthy"`           // whether it passed its health check
	Message string `json:"message,omitempty"` // optional detail ("leader", "follower", etc.)
}

// NamespaceStatus represents a namespace's status on a node.
type NamespaceStatus struct {
	Name   string `json:"name"`
	Status string `json:"status"` // "healthy", "degraded", "recovering"
}

// RQLiteNodeMetadata contains node information announced via LibP2P peer exchange.
// This struct is the single source of truth for node metadata propagated through
// the cluster. Go's json.Unmarshal silently ignores unknown fields, so old nodes
// reading metadata from new nodes simply skip the new fields — no protocol
// version change is needed.
type RQLiteNodeMetadata struct {
	// --- Existing fields (unchanged) ---

	NodeID         string    `json:"node_id"`         // RQLite node ID (raft address)
	RaftAddress    string    `json:"raft_address"`    // Raft port address (e.g., "10.0.0.1:7001")
	HTTPAddress    string    `json:"http_address"`    // HTTP API address (e.g., "10.0.0.1:5001")
	NodeType       string    `json:"node_type"`       // Node type identifier
	RaftLogIndex   uint64    `json:"raft_log_index"`  // Current Raft log index (for data comparison)
	LastSeen       time.Time `json:"last_seen"`       // Updated on every announcement
	ClusterVersion string    `json:"cluster_version"` // For compatibility checking

	// --- New: Identity ---

	// PeerID is the LibP2P peer ID of the node. Used for metadata authentication:
	// on receipt, the receiver verifies PeerID == stream sender to prevent spoofing.
	PeerID string `json:"peer_id,omitempty"`

	// WireGuardIP is the node's WireGuard VPN address (e.g., "10.0.0.1").
	WireGuardIP string `json:"wireguard_ip,omitempty"`

	// --- New: Lifecycle ---

	// LifecycleState is the node's current lifecycle state:
	// "joining", "active", "draining", or "maintenance".
	// Zero value (empty string) from old nodes is treated as "active".
	LifecycleState string `json:"lifecycle_state,omitempty"`

	// MaintenanceTTL is the time at which maintenance mode expires.
	// Only meaningful when LifecycleState == "maintenance".
	MaintenanceTTL time.Time `json:"maintenance_ttl,omitempty"`

	// --- New: Services ---

	// Services reports the status of each service running on the node.
	Services map[string]*ServiceStatus `json:"services,omitempty"`

	// Namespaces reports the status of each namespace on the node.
	Namespaces map[string]*NamespaceStatus `json:"namespaces,omitempty"`

	// --- New: Version ---

	// BinaryVersion is the node's binary version string (e.g., "1.2.3").
	BinaryVersion string `json:"binary_version,omitempty"`
}

// EffectiveLifecycleState returns the lifecycle state, defaulting to "active"
// for old nodes that don't populate the field.
func (m *RQLiteNodeMetadata) EffectiveLifecycleState() string {
	if m.LifecycleState == "" {
		return "active"
	}
	return m.LifecycleState
}

// IsInMaintenance returns true if the node has announced maintenance mode.
func (m *RQLiteNodeMetadata) IsInMaintenance() bool {
	return m.EffectiveLifecycleState() == "maintenance"
}

// IsAvailable returns true if the node is in a state that can serve requests.
func (m *RQLiteNodeMetadata) IsAvailable() bool {
	return m.EffectiveLifecycleState() == "active"
}

// IsMaintenanceExpired returns true if the node is in maintenance and the
// TTL has passed. Used by the leader's health monitor to enforce expiry.
func (m *RQLiteNodeMetadata) IsMaintenanceExpired() bool {
	if !m.IsInMaintenance() {
		return false
	}
	return !m.MaintenanceTTL.IsZero() && time.Now().After(m.MaintenanceTTL)
}

// PeerExchangeResponseV2 extends the original response with RQLite metadata.
// Kept for backward compatibility — the V1 PeerExchangeResponse in discovery.go
// already includes the same RQLiteMetadata field, so this is effectively unused.
type PeerExchangeResponseV2 struct {
	Peers          []PeerInfo          `json:"peers"`
	RQLiteMetadata *RQLiteNodeMetadata `json:"rqlite_metadata,omitempty"`
}
