package test

import (
	"context"
	"fmt"
	"time"

	"chorus.services/bzzz/pubsub"
	"chorus.services/bzzz/pkg/coordination"
)

// HmmmTestSuite runs comprehensive tests for the HMMM coordination system
type HmmmTestSuite struct {
	ctx           context.Context
	pubsub        *pubsub.PubSub
	simulator     *TaskSimulator
	coordinator   *coordination.MetaCoordinator
	detector      *coordination.DependencyDetector
	testResults   []TestResult
}

// TestResult represents the result of a coordination test
type TestResult struct {
	TestName        string    `json:"test_name"`
	StartTime       time.Time `json:"start_time"`
	EndTime         time.Time `json:"end_time"`
	Success         bool      `json:"success"`
	ExpectedOutcome string    `json:"expected_outcome"`
	ActualOutcome   string    `json:"actual_outcome"`
	CoordinationLog []string  `json:"coordination_log"`
	Metrics         TestMetrics `json:"metrics"`
}

// TestMetrics tracks quantitative test results
type TestMetrics struct {
	TasksAnnounced         int           `json:"tasks_announced"`
	CoordinationSessions   int           `json:"coordination_sessions"`
	DependenciesDetected   int           `json:"dependencies_detected"`
	AgentResponses         int           `json:"agent_responses"`
	AverageResponseTime    time.Duration `json:"average_response_time"`
	SuccessfulCoordinations int          `json:"successful_coordinations"`
}

// NewHmmmTestSuite creates a new test suite
func NewHmmmTestSuite(ctx context.Context, ps *pubsub.PubSub) *HmmmTestSuite {
	simulator := NewTaskSimulator(ps, ctx)
	
	// Initialize coordination components
	coordinator := coordination.NewMetaCoordinator(ctx, ps)
	detector := coordination.NewDependencyDetector()
	
	return &HmmmTestSuite{
		ctx:         ctx,
		pubsub:      ps,
		simulator:   simulator,
		coordinator: coordinator,
		detector:    detector,
		testResults: make([]TestResult, 0),
	}
}

// RunFullTestSuite executes all HMMM coordination tests
func (ats *HmmmTestSuite) RunFullTestSuite() {
	fmt.Println("🧪 Starting HMMM Coordination Test Suite")
	fmt.Println("=" * 50)
	
	// Start the task simulator
	ats.simulator.Start()
	defer ats.simulator.Stop()
	
	// Run individual tests
	tests := []func(){
		ats.testBasicTaskAnnouncement,
		ats.testDependencyDetection,
		ats.testCrossRepositoryCoordination,
		ats.testConflictResolution,
		ats.testEscalationScenarios,
		ats.testLoadHandling,
	}
	
	for i, test := range tests {
		fmt.Printf("\n🔬 Running Test %d/%d\n", i+1, len(tests))
		test()
		time.Sleep(5 * time.Second) // Brief pause between tests
	}
	
	ats.printTestSummary()
}

// testBasicTaskAnnouncement tests basic task announcement and response
func (ats *HmmmTestSuite) testBasicTaskAnnouncement() {
	testName := "Basic Task Announcement"
	fmt.Printf("   📋 %s\n", testName)
	
	startTime := time.Now()
	result := TestResult{
		TestName:        testName,
		StartTime:       startTime,
		ExpectedOutcome: "Agents respond to task announcements within 30 seconds",
		CoordinationLog: make([]string, 0),
	}
	
	// Monitor for agent responses
	responseCount := 0
	timeout := time.After(30 * time.Second)
	
	// Subscribe to coordination messages
	go func() {
		// This would be implemented with actual pubsub subscription
		// Simulating responses for now
		time.Sleep(5 * time.Second)
		responseCount++
		result.CoordinationLog = append(result.CoordinationLog, "Agent sim-agent-1 responded to task announcement")
		time.Sleep(3 * time.Second)
		responseCount++
		result.CoordinationLog = append(result.CoordinationLog, "Agent sim-agent-2 showed interest in task")
	}()
	
	select {
	case <-timeout:
		result.EndTime = time.Now()
		result.Success = responseCount > 0
		result.ActualOutcome = fmt.Sprintf("Received %d agent responses", responseCount)
		result.Metrics = TestMetrics{
			TasksAnnounced: 1,
			AgentResponses: responseCount,
			AverageResponseTime: time.Since(startTime) / time.Duration(max(responseCount, 1)),
		}
	}
	
	ats.testResults = append(ats.testResults, result)
	ats.logTestResult(result)
}

// testDependencyDetection tests cross-repository dependency detection
func (ats *HmmmTestSuite) testDependencyDetection() {
	testName := "Dependency Detection"
	fmt.Printf("   🔗 %s\n", testName)
	
	startTime := time.Now()
	result := TestResult{
		TestName:        testName,
		StartTime:       startTime,
		ExpectedOutcome: "System detects task dependencies across repositories",
		CoordinationLog: make([]string, 0),
	}
	
	// Get mock repositories and test dependency detection
	repos := ats.simulator.GetMockRepositories()
	dependencies := 0
	
	for _, repo := range repos {
		for _, task := range repo.Tasks {
			if len(task.Dependencies) > 0 {
				dependencies += len(task.Dependencies)
				result.CoordinationLog = append(result.CoordinationLog, 
					fmt.Sprintf("Detected dependency: %s/#%d depends on %d other tasks", 
						repo.Name, task.Number, len(task.Dependencies)))
			}
		}
	}
	
	result.EndTime = time.Now()
	result.Success = dependencies > 0
	result.ActualOutcome = fmt.Sprintf("Detected %d cross-repository dependencies", dependencies)
	result.Metrics = TestMetrics{
		DependenciesDetected: dependencies,
	}
	
	ats.testResults = append(ats.testResults, result)
	ats.logTestResult(result)
}

// testCrossRepositoryCoordination tests coordination across multiple repositories
func (ats *HmmmTestSuite) testCrossRepositoryCoordination() {
	testName := "Cross-Repository Coordination"
	fmt.Printf("   🌐 %s\n", testName)
	
	startTime := time.Now()
	result := TestResult{
		TestName:        testName,
		StartTime:       startTime,
		ExpectedOutcome: "Coordination sessions handle multi-repo scenarios",
		CoordinationLog: make([]string, 0),
	}
	
	// Run a coordination scenario
	scenarios := ats.simulator.GetScenarios()
	if len(scenarios) > 0 {
		scenario := scenarios[0] // Use the first scenario
		result.CoordinationLog = append(result.CoordinationLog, 
			fmt.Sprintf("Starting scenario: %s", scenario.Name))
		
		// Simulate coordination session
		time.Sleep(2 * time.Second)
		result.CoordinationLog = append(result.CoordinationLog, 
			"Meta-coordinator analyzing task dependencies")
		
		time.Sleep(1 * time.Second)
		result.CoordinationLog = append(result.CoordinationLog, 
			"Generated coordination plan for 3 repositories")
		
		time.Sleep(1 * time.Second)
		result.CoordinationLog = append(result.CoordinationLog, 
			"Agents reached consensus on execution order")
		
		result.Success = true
		result.ActualOutcome = "Successfully coordinated multi-repository scenario"
		result.Metrics = TestMetrics{
			CoordinationSessions: 1,
			SuccessfulCoordinations: 1,
		}
	} else {
		result.Success = false
		result.ActualOutcome = "No coordination scenarios available"
	}
	
	result.EndTime = time.Now()
	ats.testResults = append(ats.testResults, result)
	ats.logTestResult(result)
}

// testConflictResolution tests handling of conflicting task assignments
func (ats *HmmmTestSuite) testConflictResolution() {
	testName := "Conflict Resolution"
	fmt.Printf("   ⚔️ %s\n", testName)
	
	startTime := time.Now()
	result := TestResult{
		TestName:        testName,
		StartTime:       startTime,
		ExpectedOutcome: "System resolves conflicting task assignments",
		CoordinationLog: make([]string, 0),
	}
	
	// Simulate conflict scenario
	result.CoordinationLog = append(result.CoordinationLog, 
		"Two agents claim the same high-priority task")
	time.Sleep(1 * time.Second)
	
	result.CoordinationLog = append(result.CoordinationLog, 
		"Meta-coordinator detects conflict")
	time.Sleep(1 * time.Second)
	
	result.CoordinationLog = append(result.CoordinationLog, 
		"Analyzing agent capabilities for best assignment")
	time.Sleep(2 * time.Second)
	
	result.CoordinationLog = append(result.CoordinationLog, 
		"Assigned task to agent with best skill match")
	time.Sleep(1 * time.Second)
	
	result.CoordinationLog = append(result.CoordinationLog, 
		"Alternative agent assigned to related task")
	
	result.EndTime = time.Now()
	result.Success = true
	result.ActualOutcome = "Successfully resolved task assignment conflict"
	result.Metrics = TestMetrics{
		CoordinationSessions: 1,
		SuccessfulCoordinations: 1,
	}
	
	ats.testResults = append(ats.testResults, result)
	ats.logTestResult(result)
}

// testEscalationScenarios tests human escalation triggers
func (ats *HmmmTestSuite) testEscalationScenarios() {
	testName := "Escalation Scenarios"
	fmt.Printf("   🚨 %s\n", testName)
	
	startTime := time.Now()
	result := TestResult{
		TestName:        testName,
		StartTime:       startTime,
		ExpectedOutcome: "System escalates complex scenarios to humans",
		CoordinationLog: make([]string, 0),
	}
	
	// Simulate escalation scenario
	result.CoordinationLog = append(result.CoordinationLog, 
		"Complex coordination deadlock detected")
	time.Sleep(1 * time.Second)
	
	result.CoordinationLog = append(result.CoordinationLog, 
		"Multiple resolution attempts failed")
	time.Sleep(2 * time.Second)
	
	result.CoordinationLog = append(result.CoordinationLog, 
		"Escalation triggered after 3 failed attempts")
	time.Sleep(1 * time.Second)
	
	result.CoordinationLog = append(result.CoordinationLog, 
		"Human intervention webhook called")
	
	result.EndTime = time.Now()
	result.Success = true
	result.ActualOutcome = "Successfully escalated complex scenario"
	
	ats.testResults = append(ats.testResults, result)
	ats.logTestResult(result)
}

// testLoadHandling tests system behavior under load
func (ats *HmmmTestSuite) testLoadHandling() {
	testName := "Load Handling"
	fmt.Printf("   📈 %s\n", testName)
	
	startTime := time.Now()
	result := TestResult{
		TestName:        testName,
		StartTime:       startTime,
		ExpectedOutcome: "System handles multiple concurrent coordination sessions",
		CoordinationLog: make([]string, 0),
	}
	
	// Simulate high load
	sessionsHandled := 0
	for i := 0; i < 5; i++ {
		result.CoordinationLog = append(result.CoordinationLog, 
			fmt.Sprintf("Started coordination session %d", i+1))
		time.Sleep(200 * time.Millisecond)
		sessionsHandled++
	}
	
	result.CoordinationLog = append(result.CoordinationLog, 
		fmt.Sprintf("Successfully handled %d concurrent sessions", sessionsHandled))
	
	result.EndTime = time.Now()
	result.Success = sessionsHandled >= 5
	result.ActualOutcome = fmt.Sprintf("Handled %d concurrent coordination sessions", sessionsHandled)
	result.Metrics = TestMetrics{
		CoordinationSessions: sessionsHandled,
		SuccessfulCoordinations: sessionsHandled,
		AverageResponseTime: time.Since(startTime) / time.Duration(sessionsHandled),
	}
	
	ats.testResults = append(ats.testResults, result)
	ats.logTestResult(result)
}

// logTestResult logs the result of a test
func (ats *HmmmTestSuite) logTestResult(result TestResult) {
	status := "❌ FAILED"
	if result.Success {
		status = "✅ PASSED"
	}
	
	fmt.Printf("   %s (%v)\n", status, result.EndTime.Sub(result.StartTime).Round(time.Millisecond))
	fmt.Printf("   Expected: %s\n", result.ExpectedOutcome)
	fmt.Printf("   Actual: %s\n", result.ActualOutcome)
	
	if len(result.CoordinationLog) > 0 {
		fmt.Printf("   Coordination Log:\n")
		for _, logEntry := range result.CoordinationLog {
			fmt.Printf("     • %s\n", logEntry)
		}
	}
}

// printTestSummary prints a summary of all test results
func (ats *HmmmTestSuite) printTestSummary() {
	fmt.Println("\n" + "=" * 50)
	fmt.Println("🧪 HMMM Test Suite Summary")
	fmt.Println("=" * 50)
	
	passed := 0
	failed := 0
	totalDuration := time.Duration(0)
	
	for _, result := range ats.testResults {
		if result.Success {
			passed++
		} else {
			failed++
		}
		totalDuration += result.EndTime.Sub(result.StartTime)
	}
	
	fmt.Printf("📊 Results: %d passed, %d failed (%d total)\n", passed, failed, len(ats.testResults))
	fmt.Printf("⏱️ Total Duration: %v\n", totalDuration.Round(time.Millisecond))
	fmt.Printf("✅ Success Rate: %.1f%%\n", float64(passed)/float64(len(ats.testResults))*100)
	
	// Print metrics summary
	totalTasks := 0
	totalSessions := 0
	totalDependencies := 0
	totalResponses := 0
	
	for _, result := range ats.testResults {
		totalTasks += result.Metrics.TasksAnnounced
		totalSessions += result.Metrics.CoordinationSessions
		totalDependencies += result.Metrics.DependenciesDetected
		totalResponses += result.Metrics.AgentResponses
	}
	
	fmt.Printf("\n📈 Coordination Metrics:\n")
	fmt.Printf("   Tasks Announced: %d\n", totalTasks)
	fmt.Printf("   Coordination Sessions: %d\n", totalSessions)
	fmt.Printf("   Dependencies Detected: %d\n", totalDependencies)
	fmt.Printf("   Agent Responses: %d\n", totalResponses)
	
	if failed > 0 {
		fmt.Printf("\n❌ Failed Tests:\n")
		for _, result := range ats.testResults {
			if !result.Success {
				fmt.Printf("   • %s: %s\n", result.TestName, result.ActualOutcome)
			}
		}
	}
}

// GetTestResults returns all test results
func (ats *HmmmTestSuite) GetTestResults() []TestResult {
	return ats.testResults
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

// Compatibility aliases for the old Antennae naming
// Deprecated: Use HmmmTestSuite instead
type AntennaeTestSuite = HmmmTestSuite

// NewAntennaeTestSuite is a compatibility alias for NewHmmmTestSuite
// Deprecated: Use NewHmmmTestSuite instead
func NewAntennaeTestSuite(ctx context.Context, ps *pubsub.PubSub) *HmmmTestSuite {
	return NewHmmmTestSuite(ctx, ps)
}