package integration_test

import (
	"context" 
	"fmt"
	"testing"
	"time"

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

func TestElectionIntegration_ElectionLogic(t *testing.T) {
	// Test election management lifecycle
	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
	defer cancel()

	cfg := &config.Config{
		Agent: config.AgentConfig{
			ID: "test-node",
		},
		Security: config.SecurityConfig{
			ElectionConfig: config.ElectionConfig{
				Enabled:          true,
				HeartbeatTimeout: 5 * time.Second,
				ElectionTimeout:  10 * time.Second,
			},
		},
	}

	// Create a minimal election manager without full P2P (pass nils for deps we don't need)
	em := election.NewElectionManager(ctx, cfg, nil, nil, "test-node")
	if em == nil {
		t.Fatal("Expected NewElectionManager to return non-nil manager")
	}

	// Test election states
	initialState := em.GetElectionState()
	if initialState != election.StateIdle {
		t.Errorf("Expected initial state to be StateIdle, got %v", initialState)
	}

	// Test admin status methods
	currentAdmin := em.GetCurrentAdmin()
	if currentAdmin != "" {
		t.Logf("Current admin: %s", currentAdmin)
	}

	isAdmin := em.IsCurrentAdmin()
	t.Logf("Is current admin: %t", isAdmin)

	// Test trigger election (this is the real available method)
	em.TriggerElection(election.TriggerManual)

	// Test state after trigger
	newState := em.GetElectionState()
	t.Logf("State after trigger: %v", newState)

	t.Log("Election integration test completed successfully")
}

func TestElectionIntegration_AdminFailover(t *testing.T) {
	// Test admin failover scenarios using election triggers
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	cfg := &config.Config{
		Agent: config.AgentConfig{
			ID: "failover-test-node",
		},
		Security: config.SecurityConfig{
			ElectionConfig: config.ElectionConfig{
				Enabled:          true,
				HeartbeatTimeout: 3 * time.Second,
				ElectionTimeout:  6 * time.Second,
			},
		},
	}

	em := election.NewElectionManager(ctx, cfg, nil, nil, "failover-test-node")

	// Test initial state
	initialState := em.GetElectionState()
	t.Logf("Initial state: %v", initialState)

	// Test heartbeat timeout trigger (simulates admin failure)
	em.TriggerElection(election.TriggerHeartbeatTimeout)
	
	// Allow some time for state change
	time.Sleep(100 * time.Millisecond)
	
	afterFailureState := em.GetElectionState()
	t.Logf("State after heartbeat timeout: %v", afterFailureState)

	// Test split brain scenario
	em.TriggerElection(election.TriggerSplitBrain)
	
	time.Sleep(100 * time.Millisecond)
	
	splitBrainState := em.GetElectionState()
	t.Logf("State after split brain trigger: %v", splitBrainState)

	// Test quorum restoration
	em.TriggerElection(election.TriggerQuorumRestored)
	
	time.Sleep(100 * time.Millisecond)
	
	finalState := em.GetElectionState()
	t.Logf("State after quorum restored: %v", finalState)

	t.Log("Failover integration test completed")
}

func TestElectionIntegration_ConcurrentElections(t *testing.T) {
	// Test concurrent election triggers
	ctx, cancel := context.WithTimeout(context.Background(), 8*time.Second)
	defer cancel()

	cfg1 := &config.Config{
		Agent: config.AgentConfig{
			ID: "concurrent-node-1",
		},
		Security: config.SecurityConfig{
			ElectionConfig: config.ElectionConfig{
				Enabled:          true,
				HeartbeatTimeout: 4 * time.Second,
				ElectionTimeout:  8 * time.Second,
			},
		},
	}

	cfg2 := &config.Config{
		Agent: config.AgentConfig{
			ID: "concurrent-node-2",
		},
		Security: config.SecurityConfig{
			ElectionConfig: config.ElectionConfig{
				Enabled:          true,
				HeartbeatTimeout: 4 * time.Second,
				ElectionTimeout:  8 * time.Second,
			},
		},
	}

	em1 := election.NewElectionManager(ctx, cfg1, nil, nil, "concurrent-node-1")
	em2 := election.NewElectionManager(ctx, cfg2, nil, nil, "concurrent-node-2")

	// Trigger elections concurrently
	go func() {
		em1.TriggerElection(election.TriggerManual)
	}()
	
	go func() {
		em2.TriggerElection(election.TriggerManual)
	}()

	// Wait for processing
	time.Sleep(200 * time.Millisecond)

	// Check states
	state1 := em1.GetElectionState()
	state2 := em2.GetElectionState()

	t.Logf("Node 1 state: %v", state1)
	t.Logf("Node 2 state: %v", state2)

	// Both should be handling elections
	if state1 == election.StateIdle && state2 == election.StateIdle {
		t.Error("Expected at least one election manager to be in non-idle state")
	}

	t.Log("Concurrent elections test completed")
}

func TestElectionIntegration_ElectionCallbacks(t *testing.T) {
	// Test election callback system
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	cfg := &config.Config{
		Agent: config.AgentConfig{
			ID: "callback-test-node",
		},
		Security: config.SecurityConfig{
			ElectionConfig: config.ElectionConfig{
				Enabled:          true,
				HeartbeatTimeout: 5 * time.Second,
				ElectionTimeout:  10 * time.Second,
			},
		},
	}

	em := election.NewElectionManager(ctx, cfg, nil, nil, "callback-test-node")

	// Track callback invocations
	var adminChangedCalled bool
	var electionCompleteCalled bool
	var oldAdmin, newAdmin, winner string

	// Set up callbacks
	em.SetCallbacks(
		func(old, new string) {
			adminChangedCalled = true
			oldAdmin = old
			newAdmin = new
			t.Logf("Admin changed callback: %s -> %s", old, new)
		},
		func(w string) {
			electionCompleteCalled = true
			winner = w
			t.Logf("Election complete callback: winner %s", w)
		},
	)

	// Trigger election
	em.TriggerElection(election.TriggerManual)

	// Give time for potential callback execution
	time.Sleep(200 * time.Millisecond)

	// Check state changes
	currentState := em.GetElectionState()
	t.Logf("Current election state: %v", currentState)

	isAdmin := em.IsCurrentAdmin()
	t.Logf("Is current admin: %t", isAdmin)

	currentAdminID := em.GetCurrentAdmin()
	t.Logf("Current admin ID: %s", currentAdminID)

	// Log callback results
	t.Logf("Admin changed callback called: %t", adminChangedCalled)
	t.Logf("Election complete callback called: %t", electionCompleteCalled)

	if adminChangedCalled {
		t.Logf("Admin change: %s -> %s", oldAdmin, newAdmin)
	}

	if electionCompleteCalled {
		t.Logf("Election winner: %s", winner)
	}

	t.Log("Election callback integration test completed")
}