package memory

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"go.temporal.io/sdk/testsuite"
)

func TestActivityCreateKnowledge(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusCreated)
		json.NewEncoder(w).Encode(IngestResponse{ID: "chunk-123"})
	}))
	defer server.Close()

	suite := &testsuite.WorkflowTestSuite{}
	env := suite.NewTestActivityEnvironment()

	svc := NewService(server.URL, "test-token", "poimen")
	activities := NewActivities(svc)

	env.RegisterActivity(activities.CreateKnowledgeActivity)

	record := &KnowledgeRecord{
		Level:   "L1",
		Content: "test",
	}

	result, err := env.ExecuteActivity(activities.CreateKnowledgeActivity, record)

	if err != nil {
		t.Fatalf("activity failed: %v", err)
	}

	var id string
	if err := result.Get(&id); err != nil {
		t.Fatalf("get result failed: %v", err)
	}

	if id != "chunk-123" {
		t.Errorf("expected chunk-123, got %s", id)
	}
}

func TestActivitySearchKnowledge(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(QueryResponse{
			Results: []QueryResult{
				{
					ID:   "chunk-123",
					Text: "matching knowledge",
				},
			},
		})
	}))
	defer server.Close()

	suite := &testsuite.WorkflowTestSuite{}
	env := suite.NewTestActivityEnvironment()

	svc := NewService(server.URL, "test-token", "poimen")
	activities := NewActivities(svc)

	env.RegisterActivity(activities.SearchKnowledgeActivity)

	result, err := env.ExecuteActivity(activities.SearchKnowledgeActivity, "test query", nil)

	if err != nil {
		t.Fatalf("activity failed: %v", err)
	}

	var records []KnowledgeRecord
	if err := result.Get(&records); err != nil {
		t.Fatalf("get result failed: %v", err)
	}

	if len(records) != 1 {
		t.Errorf("expected 1 record, got %d", len(records))
	}
}

func TestActivityGetContext(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(ContextResponse{
			Tier: 1,
			Lessons: []ContextLesson{
				{
					Tier: 1,
					Text: "lesson text",
				},
			},
		})
	}))
	defer server.Close()

	suite := &testsuite.WorkflowTestSuite{}
	env := suite.NewTestActivityEnvironment()

	svc := NewService(server.URL, "test-token", "poimen")
	activities := NewActivities(svc)

	env.RegisterActivity(activities.GetContextActivity)

	result, err := env.ExecuteActivity(activities.GetContextActivity, "kubectl", "debug", 8192)

	if err != nil {
		t.Fatalf("activity failed: %v", err)
	}

	var ctx *ServiceContext
	if err := result.Get(&ctx); err != nil {
		t.Fatalf("get result failed: %v", err)
	}

	if ctx.Tier != 1 {
		t.Errorf("expected tier 1, got %d", ctx.Tier)
	}

	if len(ctx.Lessons) != 1 {
		t.Errorf("expected 1 lesson, got %d", len(ctx.Lessons))
	}
}

func TestActivityDiagnoseIssue(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(ContextResponse{
			Tier: 1,
			Lessons: []ContextLesson{
				{
					Tier: 1,
					Text: "diagnosis: check logs",
				},
			},
			Skills: []ContextSkill{
				{
					Name: "debug-skill",
					Why:  "matched",
				},
			},
		})
	}))
	defer server.Close()

	suite := &testsuite.WorkflowTestSuite{}
	env := suite.NewTestActivityEnvironment()

	svc := NewService(server.URL, "test-token", "poimen")
	activities := NewActivities(svc)

	env.RegisterActivity(activities.DiagnoseIssueActivity)

	result, err := env.ExecuteActivity(activities.DiagnoseIssueActivity, "kubectl", "pod-crash")

	if err != nil {
		t.Fatalf("activity failed: %v", err)
	}

	var recommendations []string
	if err := result.Get(&recommendations); err != nil {
		t.Fatalf("get result failed: %v", err)
	}

	if len(recommendations) == 0 {
		t.Error("expected recommendations")
	}
}

func TestActivityAnalyzeError(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(QueryResponse{
			Results: []QueryResult{
				{
					ID:    "chunk-123",
					Level: "L1",
					Text:  "solution: restart pod",
				},
			},
		})
	}))
	defer server.Close()

	suite := &testsuite.WorkflowTestSuite{}
	env := suite.NewTestActivityEnvironment()

	svc := NewService(server.URL, "test-token", "poimen")
	activities := NewActivities(svc)

	env.RegisterActivity(activities.AnalyzeErrorActivity)

	result, err := env.ExecuteActivity(activities.AnalyzeErrorActivity, "CrashLoopBackOff")

	if err != nil {
		t.Fatalf("activity failed: %v", err)
	}

	var records []KnowledgeRecord
	if err := result.Get(&records); err != nil {
		t.Fatalf("get result failed: %v", err)
	}

	if len(records) != 1 {
		t.Errorf("expected 1 record, got %d", len(records))
	}
}

func TestActivityHealthCheck(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}))
	defer server.Close()

	suite := &testsuite.WorkflowTestSuite{}
	env := suite.NewTestActivityEnvironment()

	svc := NewService(server.URL, "test-token", "poimen")
	activities := NewActivities(svc)

	env.RegisterActivity(activities.HealthCheckActivity)

	result, err := env.ExecuteActivity(activities.HealthCheckActivity)

	if err != nil {
		t.Fatalf("activity failed: %v", err)
	}

	var healthy bool
	if err := result.Get(&healthy); err != nil {
		t.Fatalf("get result failed: %v", err)
	}

	if !healthy {
		t.Error("expected healthy")
	}
}

func TestActivityLearnFromExecution(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusCreated)
		json.NewEncoder(w).Encode(IngestResponse{ID: "chunk-456"})
	}))
	defer server.Close()

	suite := &testsuite.WorkflowTestSuite{}
	env := suite.NewTestActivityEnvironment()

	svc := NewService(server.URL, "test-token", "poimen")
	activities := NewActivities(svc)

	env.RegisterActivity(activities.LearnFromExecutionActivity)

	result, err := env.ExecuteActivity(activities.LearnFromExecutionActivity, "task-123", "success", []string{"tag1"})

	if err != nil {
		t.Fatalf("activity failed: %v", err)
	}

	var id string
	if err := result.Get(&id); err != nil {
		t.Fatalf("get result failed: %v", err)
	}

	if id != "chunk-456" {
		t.Errorf("expected chunk-456, got %s", id)
	}
}

func TestActivityDocumentDecision(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusCreated)
		json.NewEncoder(w).Encode(IngestResponse{ID: "chunk-789"})
	}))
	defer server.Close()

	suite := &testsuite.WorkflowTestSuite{}
	env := suite.NewTestActivityEnvironment()

	svc := NewService(server.URL, "test-token", "poimen")
	activities := NewActivities(svc)

	env.RegisterActivity(activities.DocumentDecisionActivity)

	result, err := env.ExecuteActivity(
		activities.DocumentDecisionActivity,
		"scaling",
		"scale to 5 replicas",
		"high CPU usage",
	)

	if err != nil {
		t.Fatalf("activity failed: %v", err)
	}

	var id string
	if err := result.Get(&id); err != nil {
		t.Fatalf("get result failed: %v", err)
	}

	if id != "chunk-789" {
		t.Errorf("expected chunk-789, got %s", id)
	}
}

func TestActivityOptions(t *testing.T) {
	opts := DefaultActivityOptions()

	if opts.RetryAttempts != 3 {
		t.Errorf("expected 3 retry attempts, got %d", opts.RetryAttempts)
	}

	if opts.StartTimeout == 0 {
		t.Error("expected non-zero start timeout")
	}
}

func TestActivityError(t *testing.T) {
	err := &MemoryActivityError{
		ActivityName: "test-activity",
		Attempt:      2,
		Err:          context.Canceled,
	}

	msg := err.Error()
	if msg == "" {
		t.Error("expected error message")
	}

	if !contains(msg, "test-activity") {
		t.Error("expected activity name in error")
	}

	if !contains(msg, "attempt 2") {
		t.Error("expected attempt number in error")
	}
}

func contains(s, substr string) bool {
	for i := 0; i < len(s)-len(substr)+1; i++ {
		if s[i:i+len(substr)] == substr {
			return true
		}
	}
	return false
}
