package memory

import (
	"testing"
	"time"
)

func TestChangeDetector_DetectNew(t *testing.T) {
	d := NewChangeDetector(ChangeDetectorConfig{MaxChanges: 100})

	// First detection - should see new resource
	snapshots := []ResourceSnapshot{
		{ID: "vm-100", Name: "web-server", Type: "vm", Status: "running", Node: "node1"},
	}

	changes := d.DetectChanges(snapshots)
	if len(changes) != 1 {
		t.Errorf("Expected 1 change (creation), got %d", len(changes))
	}
	if changes[0].ChangeType != ChangeCreated {
		t.Errorf("Expected ChangeCreated, got %s", changes[0].ChangeType)
	}
}

func TestChangeDetector_DetectStatusChange(t *testing.T) {
	d := NewChangeDetector(ChangeDetectorConfig{MaxChanges: 100})

	// Initial state
	d.DetectChanges([]ResourceSnapshot{
		{ID: "vm-100", Name: "web-server", Type: "vm", Status: "running", Node: "node1"},
	})

	// Status change
	changes := d.DetectChanges([]ResourceSnapshot{
		{ID: "vm-100", Name: "web-server", Type: "vm", Status: "stopped", Node: "node1"},
	})

	if len(changes) != 1 {
		t.Errorf("Expected 1 status change, got %d", len(changes))
	}
	if changes[0].ChangeType != ChangeStatus {
		t.Errorf("Expected ChangeStatus, got %s", changes[0].ChangeType)
	}
	if changes[0].Before != "running" || changes[0].After != "stopped" {
		t.Errorf("Expected running->stopped, got %v->%v", changes[0].Before, changes[0].After)
	}
}

func TestChangeDetector_DetectMigration(t *testing.T) {
	d := NewChangeDetector(ChangeDetectorConfig{MaxChanges: 100})

	// Initial state
	d.DetectChanges([]ResourceSnapshot{
		{ID: "vm-100", Name: "web-server", Type: "vm", Status: "running", Node: "node1"},
	})

	// Migration
	changes := d.DetectChanges([]ResourceSnapshot{
		{ID: "vm-100", Name: "web-server", Type: "vm", Status: "running", Node: "node2"},
	})

	if len(changes) != 1 {
		t.Errorf("Expected 1 migration change, got %d", len(changes))
	}
	if changes[0].ChangeType != ChangeMigrated {
		t.Errorf("Expected ChangeMigrated, got %s", changes[0].ChangeType)
	}
}

func TestChangeDetector_DetectDeleted(t *testing.T) {
	d := NewChangeDetector(ChangeDetectorConfig{MaxChanges: 100})

	// Initial state
	d.DetectChanges([]ResourceSnapshot{
		{ID: "vm-100", Name: "web-server", Type: "vm", Status: "running", Node: "node1"},
	})

	// Delete (empty snapshot)
	changes := d.DetectChanges([]ResourceSnapshot{})

	if len(changes) != 1 {
		t.Errorf("Expected 1 deletion change, got %d", len(changes))
	}
	if changes[0].ChangeType != ChangeDeleted {
		t.Errorf("Expected ChangeDeleted, got %s", changes[0].ChangeType)
	}
}

func TestChangeDetector_NoChanges(t *testing.T) {
	d := NewChangeDetector(ChangeDetectorConfig{MaxChanges: 100})

	snapshot := []ResourceSnapshot{
		{ID: "vm-100", Name: "web-server", Type: "vm", Status: "running", Node: "node1"},
	}

	// First time - creates
	d.DetectChanges(snapshot)

	// Second time - no changes
	changes := d.DetectChanges(snapshot)
	if len(changes) != 0 {
		t.Errorf("Expected 0 changes, got %d", len(changes))
	}
}

func TestChangeDetector_GetChangesForResource(t *testing.T) {
	d := NewChangeDetector(ChangeDetectorConfig{MaxChanges: 100})

	// Create and change a few times
	d.DetectChanges([]ResourceSnapshot{
		{ID: "vm-100", Name: "web", Type: "vm", Status: "stopped", Node: "node1"},
		{ID: "vm-200", Name: "db", Type: "vm", Status: "running", Node: "node1"},
	})
	d.DetectChanges([]ResourceSnapshot{
		{ID: "vm-100", Name: "web", Type: "vm", Status: "running", Node: "node1"},
		{ID: "vm-200", Name: "db", Type: "vm", Status: "running", Node: "node1"},
	})

	// Get changes for vm-100 only
	changes := d.GetChangesForResource("vm-100", 10)
	for _, c := range changes {
		if c.ResourceID != "vm-100" {
			t.Errorf("Got change for wrong resource: %s", c.ResourceID)
		}
	}
}

func TestRemediationLog_LogAndRetrieve(t *testing.T) {
	r := NewRemediationLog(RemediationLogConfig{MaxRecords: 100})

	r.Log(RemediationRecord{
		ResourceID: "vm-100",
		Problem:    "High memory usage",
		Action:     "systemctl restart nginx",
		Outcome:    OutcomeResolved,
	})

	records := r.GetForResource("vm-100", 10)
	if len(records) != 1 {
		t.Errorf("Expected 1 record, got %d", len(records))
	}
	if records[0].Action != "systemctl restart nginx" {
		t.Errorf("Wrong action: %s", records[0].Action)
	}
}

func TestRemediationLog_GetSimilar(t *testing.T) {
	r := NewRemediationLog(RemediationLogConfig{MaxRecords: 100})

	// Log some remediations
	r.Log(RemediationRecord{
		ResourceID: "vm-100",
		Problem:    "High memory usage causing OOM",
		Action:     "Restart service",
		Outcome:    OutcomeResolved,
	})
	r.Log(RemediationRecord{
		ResourceID: "vm-200",
		Problem:    "Memory leak detected",
		Action:     "Cleared cache",
		Outcome:    OutcomePartial,
	})
	r.Log(RemediationRecord{
		ResourceID: "vm-300",
		Problem:    "CPU spike from backup",
		Action:     "Rescheduled backup",
		Outcome:    OutcomeResolved,
	})

	// Search for similar memory issues
	similar := r.GetSimilar("High memory usage causing slowdown", 5)
	if len(similar) < 1 {
		t.Errorf("Expected at least 1 similar record")
	}
}

func TestRemediationLog_GetSuccessfulRemediations(t *testing.T) {
	r := NewRemediationLog(RemediationLogConfig{MaxRecords: 100})

	r.Log(RemediationRecord{
		Problem: "Memory usage high",
		Action:  "Restart service",
		Outcome: OutcomeResolved,
	})
	r.Log(RemediationRecord{
		Problem: "Memory usage high",
		Action:  "Kill process",
		Outcome: OutcomeFailed,
	})

	successful := r.GetSuccessfulRemediations("Memory usage issue", 5)
	for _, rec := range successful {
		if rec.Outcome != OutcomeResolved && rec.Outcome != OutcomePartial {
			t.Errorf("Got unsuccessful remediation in successful list: %s", rec.Outcome)
		}
	}
}

func TestRemediationLog_Stats(t *testing.T) {
	r := NewRemediationLog(RemediationLogConfig{MaxRecords: 100})

	r.Log(RemediationRecord{Problem: "p1", Action: "a1", Outcome: OutcomeResolved})
	r.Log(RemediationRecord{Problem: "p2", Action: "a2", Outcome: OutcomeResolved})
	r.Log(RemediationRecord{Problem: "p3", Action: "a3", Outcome: OutcomeFailed})

	stats := r.GetRemediationStats()
	if stats["total"] != 3 {
		t.Errorf("Expected 3 total, got %d", stats["total"])
	}
	if stats["resolved"] != 2 {
		t.Errorf("Expected 2 resolved, got %d", stats["resolved"])
	}
	if stats["failed"] != 1 {
		t.Errorf("Expected 1 failed, got %d", stats["failed"])
	}
}

func TestChangeDetector_GetRecentChanges(t *testing.T) {
	d := NewChangeDetector(ChangeDetectorConfig{MaxChanges: 100})

	// Create some changes
	d.DetectChanges([]ResourceSnapshot{
		{ID: "vm-100", Name: "web", Type: "vm", Status: "running", Node: "node1"},
	})

	// Get recent changes
	since := time.Now().Add(-1 * time.Hour)
	changes := d.GetRecentChanges(10, since)
	if len(changes) == 0 {
		t.Error("Expected at least 1 recent change")
	}
}
