package leader

import (
	"context"
	"fmt"
	"log"
	"sync"
	"time"

	"chorus.services/bzzz/pkg/election"
	"chorus.services/bzzz/pkg/dht"
	"chorus.services/bzzz/pkg/slurp/intelligence"
	"chorus.services/bzzz/pkg/slurp/storage"
	slurpContext "chorus.services/bzzz/pkg/slurp/context"
)

// ElectionIntegratedContextManager integrates SLURP context management with BZZZ election system
type ElectionIntegratedContextManager struct {
	*LeaderContextManager // Embed the base context manager
	
	// Election integration
	electionMu       sync.RWMutex
	slurpElection    election.SLURPElection
	electionTerm     int64
	
	// Leadership state tracking
	leadershipEvents chan LeadershipEvent
	eventHandlers    []LeadershipEventHandler
	
	// Integration configuration
	config           *ElectionIntegrationConfig
	
	// Synchronization
	integrationWg    sync.WaitGroup
	integrationStop  chan struct{}
}

// LeadershipEvent represents a leadership change event
type LeadershipEvent struct {
	Type          LeadershipEventType `json:"type"`           // Type of event
	OldLeaderID   string              `json:"old_leader_id"`  // Previous leader
	NewLeaderID   string              `json:"new_leader_id"`  // New leader
	Term          int64               `json:"term"`           // Election term
	Timestamp     time.Time           `json:"timestamp"`      // When event occurred
	NodeID        string              `json:"node_id"`        // Node reporting event
	Metadata      map[string]interface{} `json:"metadata"`    // Additional event data
}

// LeadershipEventType represents types of leadership events
type LeadershipEventType string

const (
	LeadershipEventBecameLeader  LeadershipEventType = "became_leader"   // Node became leader
	LeadershipEventLostLeadership LeadershipEventType = "lost_leadership" // Node lost leadership
	LeadershipEventLeaderChanged  LeadershipEventType = "leader_changed"  // Leader changed (any node)
	LeadershipEventElectionStart  LeadershipEventType = "election_start"  // Election started
	LeadershipEventElectionEnd    LeadershipEventType = "election_end"    // Election completed
	LeadershipEventFailover      LeadershipEventType = "failover"        // Leadership failover
)

// LeadershipEventHandler handles leadership events
type LeadershipEventHandler func(event LeadershipEvent) error

// ElectionIntegrationConfig configures election integration
type ElectionIntegrationConfig struct {
	// Event processing
	EventBufferSize       int           `json:"event_buffer_size"`        // Event buffer size
	EventProcessingTimeout time.Duration `json:"event_processing_timeout"` // Event processing timeout
	MaxEventHandlers      int           `json:"max_event_handlers"`       // Maximum event handlers
	
	// Leadership transition
	TransitionTimeout     time.Duration `json:"transition_timeout"`       // Leadership transition timeout
	StatePreservation     bool          `json:"state_preservation"`       // Preserve state on transition
	GracefulShutdown      bool          `json:"graceful_shutdown"`        // Graceful shutdown on leadership loss
	
	// Monitoring
	HealthCheckInterval   time.Duration `json:"health_check_interval"`    // Health check interval
	MetricsReporting      bool          `json:"metrics_reporting"`        // Enable metrics reporting
	DetailedLogging       bool          `json:"detailed_logging"`         // Enable detailed logging
}

// NewElectionIntegratedContextManager creates a new election-integrated context manager
func NewElectionIntegratedContextManager(
	slurpElection election.SLURPElection,
	dht dht.DHT,
	intelligence intelligence.IntelligenceEngine,
	storage storage.ContextStore,
	resolver slurpContext.ContextResolver,
	config *ElectionIntegrationConfig,
) (*ElectionIntegratedContextManager, error) {
	if config == nil {
		config = DefaultElectionIntegrationConfig()
	}
	
	// Create base context manager
	baseManager := NewContextManager(
		&electionAdapter{slurpElection}, // Adapt SLURP election to base election interface
		dht,
		intelligence,
		storage,
		resolver,
	)
	
	eicm := &ElectionIntegratedContextManager{
		LeaderContextManager: baseManager.(*LeaderContextManager),
		slurpElection:        slurpElection,
		leadershipEvents:     make(chan LeadershipEvent, config.EventBufferSize),
		eventHandlers:        make([]LeadershipEventHandler, 0, config.MaxEventHandlers),
		config:               config,
		integrationStop:      make(chan struct{}),
	}
	
	// Register with election system
	if err := slurpElection.RegisterContextManager(eicm); err != nil {
		return nil, fmt.Errorf("failed to register with election system: %w", err)
	}
	
	// Set up election callbacks
	callbacks := &election.ContextLeadershipCallbacks{
		OnBecomeContextLeader:     eicm.onBecomeContextLeader,
		OnLoseContextLeadership:   eicm.onLoseContextLeadership,
		OnContextLeaderChanged:    eicm.onContextLeaderChanged,
		OnContextGenerationStarted: eicm.onContextGenerationStarted,
		OnContextGenerationStopped: eicm.onContextGenerationStopped,
		OnContextFailover:         eicm.onContextFailover,
		OnContextError:            eicm.onContextError,
	}
	
	if err := slurpElection.SetContextLeadershipCallbacks(callbacks); err != nil {
		return nil, fmt.Errorf("failed to set election callbacks: %w", err)
	}
	
	// Start event processing
	eicm.integrationWg.Add(1)
	go eicm.processLeadershipEvents()
	
	if config.DetailedLogging {
		log.Printf("✅ Election-integrated context manager created")
	}
	
	return eicm, nil
}

// IsLeader returns whether this node is the current leader (overrides base implementation)
func (eicm *ElectionIntegratedContextManager) IsLeader() bool {
	return eicm.slurpElection.IsContextLeader()
}

// WaitForLeadership blocks until this node becomes leader
func (eicm *ElectionIntegratedContextManager) WaitForLeadership(ctx context.Context) error {
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()
	
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-ticker.C:
			if eicm.IsLeader() {
				return nil
			}
		}
	}
}

// GetLeaderInfo returns information about current leader
func (eicm *ElectionIntegratedContextManager) GetLeaderInfo() (*LeaderInfo, error) {
	return eicm.slurpElection.GetContextLeaderInfo()
}

// TransferLeadership initiates graceful leadership transfer
func (eicm *ElectionIntegratedContextManager) TransferLeadership(ctx context.Context, targetNodeID string) error {
	return eicm.slurpElection.TransferContextLeadership(ctx, targetNodeID)
}

// RequestFromLeader allows non-leader nodes to request context from leader
func (eicm *ElectionIntegratedContextManager) RequestFromLeader(req *ContextGenerationRequest) (*ContextGenerationResult, error) {
	if eicm.IsLeader() {
		// We are the leader, process directly
		if err := eicm.RequestContextGeneration(req); err != nil {
			return &ContextGenerationResult{
				RequestID:   req.ID,
				Success:     false,
				Error:       err.Error(),
				GeneratedAt: time.Now(),
				GeneratedBy: eicm.getNodeID(),
			}, nil
		}
		
		// TODO: Wait for completion and return result
		// For now, return success
		return &ContextGenerationResult{
			RequestID:   req.ID,
			Success:     true,
			GeneratedAt: time.Now(),
			GeneratedBy: eicm.getNodeID(),
		}, nil
	}
	
	// We are not the leader, forward to leader
	return eicm.forwardToLeader(req)
}

// AddLeadershipEventHandler adds a handler for leadership events
func (eicm *ElectionIntegratedContextManager) AddLeadershipEventHandler(handler LeadershipEventHandler) error {
	eicm.electionMu.Lock()
	defer eicm.electionMu.Unlock()
	
	if len(eicm.eventHandlers) >= eicm.config.MaxEventHandlers {
		return fmt.Errorf("maximum event handlers (%d) reached", eicm.config.MaxEventHandlers)
	}
	
	eicm.eventHandlers = append(eicm.eventHandlers, handler)
	return nil
}

// GetElectionTerm returns current election term
func (eicm *ElectionIntegratedContextManager) GetElectionTerm() int64 {
	eicm.electionMu.RLock()
	defer eicm.electionMu.RUnlock()
	return eicm.electionTerm
}

// GetElectionStatus returns current election integration status
func (eicm *ElectionIntegratedContextManager) GetElectionStatus() *ElectionIntegrationStatus {
	eicm.electionMu.RLock()
	defer eicm.electionMu.RUnlock()
	
	return &ElectionIntegrationStatus{
		IsIntegrated:        true,
		IsContextLeader:     eicm.IsLeader(),
		CurrentTerm:         eicm.electionTerm,
		EventHandlers:       len(eicm.eventHandlers),
		PendingEvents:       len(eicm.leadershipEvents),
		LastUpdate:          time.Now(),
	}
}

// Election callback implementations

func (eicm *ElectionIntegratedContextManager) onBecomeContextLeader(ctx context.Context, term int64) error {
	if eicm.config.DetailedLogging {
		log.Printf("🎯 Became context leader (term: %d)", term)
	}
	
	eicm.electionMu.Lock()
	eicm.electionTerm = term
	eicm.electionMu.Unlock()
	
	event := LeadershipEvent{
		Type:        LeadershipEventBecameLeader,
		NewLeaderID: eicm.getNodeID(),
		Term:        term,
		Timestamp:   time.Now(),
		NodeID:      eicm.getNodeID(),
	}
	
	eicm.emitEvent(event)
	return nil
}

func (eicm *ElectionIntegratedContextManager) onLoseContextLeadership(ctx context.Context, newLeader string) error {
	if eicm.config.DetailedLogging {
		log.Printf("📤 Lost context leadership to %s", newLeader)
	}
	
	event := LeadershipEvent{
		Type:        LeadershipEventLostLeadership,
		OldLeaderID: eicm.getNodeID(),
		NewLeaderID: newLeader,
		Term:        eicm.electionTerm,
		Timestamp:   time.Now(),
		NodeID:      eicm.getNodeID(),
	}
	
	eicm.emitEvent(event)
	
	// Graceful shutdown if configured
	if eicm.config.GracefulShutdown {
		return eicm.performGracefulShutdown(ctx)
	}
	
	return nil
}

func (eicm *ElectionIntegratedContextManager) onContextLeaderChanged(oldLeader, newLeader string, term int64) {
	if eicm.config.DetailedLogging {
		log.Printf("🔄 Context leader changed: %s -> %s (term: %d)", oldLeader, newLeader, term)
	}
	
	eicm.electionMu.Lock()
	eicm.electionTerm = term
	eicm.electionMu.Unlock()
	
	event := LeadershipEvent{
		Type:        LeadershipEventLeaderChanged,
		OldLeaderID: oldLeader,
		NewLeaderID: newLeader,
		Term:        term,
		Timestamp:   time.Now(),
		NodeID:      eicm.getNodeID(),
	}
	
	eicm.emitEvent(event)
}

func (eicm *ElectionIntegratedContextManager) onContextGenerationStarted(leaderID string) {
	if eicm.config.DetailedLogging {
		log.Printf("🚀 Context generation started by %s", leaderID)
	}
	
	event := LeadershipEvent{
		Type:        LeadershipEventElectionEnd,
		NewLeaderID: leaderID,
		Term:        eicm.electionTerm,
		Timestamp:   time.Now(),
		NodeID:      eicm.getNodeID(),
		Metadata: map[string]interface{}{
			"generation_started": true,
		},
	}
	
	eicm.emitEvent(event)
}

func (eicm *ElectionIntegratedContextManager) onContextGenerationStopped(leaderID string, reason string) {
	if eicm.config.DetailedLogging {
		log.Printf("⏹️ Context generation stopped by %s (reason: %s)", leaderID, reason)
	}
	
	event := LeadershipEvent{
		Type:        LeadershipEventElectionEnd,
		OldLeaderID: leaderID,
		Term:        eicm.electionTerm,
		Timestamp:   time.Now(),
		NodeID:      eicm.getNodeID(),
		Metadata: map[string]interface{}{
			"generation_stopped": true,
			"reason":            reason,
		},
	}
	
	eicm.emitEvent(event)
}

func (eicm *ElectionIntegratedContextManager) onContextFailover(oldLeader, newLeader string, duration time.Duration) {
	if eicm.config.DetailedLogging {
		log.Printf("🔄 Context failover: %s -> %s (duration: %v)", oldLeader, newLeader, duration)
	}
	
	event := LeadershipEvent{
		Type:        LeadershipEventFailover,
		OldLeaderID: oldLeader,
		NewLeaderID: newLeader,
		Term:        eicm.electionTerm,
		Timestamp:   time.Now(),
		NodeID:      eicm.getNodeID(),
		Metadata: map[string]interface{}{
			"failover_duration": duration,
		},
	}
	
	eicm.emitEvent(event)
}

func (eicm *ElectionIntegratedContextManager) onContextError(err error, severity election.ErrorSeverity) {
	if eicm.config.DetailedLogging {
		log.Printf("⚠️ Context error (%s): %v", severity, err)
	}
	
	// TODO: Handle errors based on severity
	// Could trigger failover for critical errors
}

// Event processing

func (eicm *ElectionIntegratedContextManager) emitEvent(event LeadershipEvent) {
	select {
	case eicm.leadershipEvents <- event:
		// Event queued successfully
	default:
		// Event buffer full, log warning
		log.Printf("⚠️ Leadership event buffer full, dropping event: %s", event.Type)
	}
}

func (eicm *ElectionIntegratedContextManager) processLeadershipEvents() {
	defer eicm.integrationWg.Done()
	
	for {
		select {
		case event := <-eicm.leadershipEvents:
			eicm.handleLeadershipEvent(event)
		case <-eicm.integrationStop:
			return
		}
	}
}

func (eicm *ElectionIntegratedContextManager) handleLeadershipEvent(event LeadershipEvent) {
	eicm.electionMu.RLock()
	handlers := make([]LeadershipEventHandler, len(eicm.eventHandlers))
	copy(handlers, eicm.eventHandlers)
	eicm.electionMu.RUnlock()
	
	for _, handler := range handlers {
		ctx, cancel := context.WithTimeout(context.Background(), eicm.config.EventProcessingTimeout)
		
		func() {
			defer cancel()
			defer func() {
				if r := recover(); r != nil {
					log.Printf("❌ Event handler panicked: %v", r)
				}
			}()
			
			if err := handler(event); err != nil {
				log.Printf("⚠️ Event handler error: %v", err)
			}
		}()
	}
}

// Utility methods

func (eicm *ElectionIntegratedContextManager) getNodeID() string {
	// TODO: Get actual node ID from election system or config
	return "node-" + fmt.Sprintf("%d", time.Now().Unix())
}

func (eicm *ElectionIntegratedContextManager) forwardToLeader(req *ContextGenerationRequest) (*ContextGenerationResult, error) {
	// TODO: Implement request forwarding to current leader
	return &ContextGenerationResult{
		RequestID:   req.ID,
		Success:     false,
		Error:       "request forwarding not implemented",
		GeneratedAt: time.Now(),
	}, nil
}

func (eicm *ElectionIntegratedContextManager) performGracefulShutdown(ctx context.Context) error {
	// TODO: Implement graceful shutdown logic
	// - Finish current tasks
	// - Transfer pending tasks
	// - Clean up resources
	return nil
}

// Stop gracefully stops the integrated context manager
func (eicm *ElectionIntegratedContextManager) Stop() {
	if eicm.config.DetailedLogging {
		log.Printf("🛑 Stopping election-integrated context manager")
	}
	
	// Signal stop to event processing
	close(eicm.integrationStop)
	
	// Wait for event processing to complete
	eicm.integrationWg.Wait()
	
	// Stop base context manager
	if eicm.LeaderContextManager != nil {
		// TODO: Add Stop method to base context manager
	}
	
	if eicm.config.DetailedLogging {
		log.Printf("✅ Election-integrated context manager stopped")
	}
}

// Supporting types

// ElectionIntegrationStatus represents status of election integration
type ElectionIntegrationStatus struct {
	IsIntegrated    bool      `json:"is_integrated"`     // Whether integration is active
	IsContextLeader bool      `json:"is_context_leader"` // Whether this node is context leader
	CurrentTerm     int64     `json:"current_term"`      // Current election term
	EventHandlers   int       `json:"event_handlers"`    // Number of event handlers
	PendingEvents   int       `json:"pending_events"`    // Number of pending events
	LastUpdate      time.Time `json:"last_update"`       // When status was last updated
}

// DefaultElectionIntegrationConfig returns default integration configuration
func DefaultElectionIntegrationConfig() *ElectionIntegrationConfig {
	return &ElectionIntegrationConfig{
		EventBufferSize:        100,
		EventProcessingTimeout: 10 * time.Second,
		MaxEventHandlers:       10,
		TransitionTimeout:      30 * time.Second,
		StatePreservation:      true,
		GracefulShutdown:       true,
		HealthCheckInterval:    30 * time.Second,
		MetricsReporting:       true,
		DetailedLogging:        false,
	}
}

// electionAdapter adapts SLURPElection to base Election interface
type electionAdapter struct {
	slurpElection election.SLURPElection
}

func (ea *electionAdapter) IsLeader() bool {
	return ea.slurpElection.IsContextLeader()
}

func (ea *electionAdapter) GetCurrentAdmin() string {
	return ea.slurpElection.GetCurrentAdmin()
}

func (ea *electionAdapter) Start() error {
	return ea.slurpElection.Start()
}

func (ea *electionAdapter) Stop() {
	ea.slurpElection.Stop()
}

func (ea *electionAdapter) TriggerElection(trigger election.ElectionTrigger) {
	ea.slurpElection.TriggerElection(trigger)
}

func (ea *electionAdapter) IsCurrentAdmin() bool {
	return ea.slurpElection.IsCurrentAdmin()
}

func (ea *electionAdapter) GetElectionState() election.ElectionState {
	return ea.slurpElection.GetElectionState()
}

func (ea *electionAdapter) SetCallbacks(onAdminChanged func(string, string), onElectionComplete func(string)) {
	ea.slurpElection.SetCallbacks(onAdminChanged, onElectionComplete)
}

func (ea *electionAdapter) SendAdminHeartbeat() error {
	return ea.slurpElection.SendAdminHeartbeat()
}