package memory

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

func TestServiceCreateKnowledge(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/memory/ingest" {
			t.Errorf("unexpected path: %s", r.URL.Path)
		}

		var req IngestRequest
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			t.Fatalf("decode request: %v", err)
		}

		if req.Project != "poimen" {
			t.Errorf("expected project poimen, got %s", req.Project)
		}

		w.WriteHeader(http.StatusCreated)
		json.NewEncoder(w).Encode(IngestResponse{
			ID:          "chunk-123",
			QueueStatus: "pending",
		})
	}))
	defer server.Close()

	svc := NewService(server.URL, "test-token", "poimen")
	id, err := svc.CreateKnowledge(context.Background(), &KnowledgeRecord{
		Content: "test knowledge",
		Level:   "L1",
	})

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

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

func TestServiceRetrieveKnowledge(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/memory/query" {
			t.Errorf("unexpected path: %s", r.URL.Path)
		}

		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(QueryResponse{
			Query: "test",
			Results: []QueryResult{
				{
					ID:            "chunk-123",
					Level:         "L1",
					Score:         0.95,
					SemanticScore: 0.96,
					LexicalScore:  0.94,
					Text:          "knowledge content",
					Breadcrumb:    "path > to > doc",
					Source:        "test",
				},
			},
			TotalHits:    1,
			SearchTimeMS: 50,
		})
	}))
	defer server.Close()

	svc := NewService(server.URL, "test-token", "poimen")
	records, err := svc.RetrieveKnowledge(context.Background(), "test", nil)

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

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

	if records[0].Content != "knowledge content" {
		t.Errorf("unexpected content")
	}

	meta := records[0].Metadata
	if score, ok := meta["score"].(float32); ok {
		if score != 0.95 {
			t.Errorf("expected score 0.95, got %f", score)
		}
	}
}

func TestServiceRetrieveContext(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/memory/context" {
			t.Errorf("unexpected path: %s", r.URL.Path)
		}

		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(ContextResponse{
			Tier: 1,
			Lessons: []ContextLesson{
				{
					Tier:        1,
					Level:       "L1",
					Score:       1.0,
					Text:        "first lesson",
					MatchedKind: "signature",
				},
				{
					Tier:  2,
					Level: "L2",
					Score: 0.87,
					Text:  "second lesson",
				},
			},
			Skills: []ContextSkill{
				{
					Name: "debug-skill",
					Why:  "tier 1 matched",
				},
			},
			Budget: ContextBudget{
				Requested: 8192,
				Used:      2048,
				Dropped:   0,
			},
		})
	}))
	defer server.Close()

	svc := NewService(server.URL, "test-token", "poimen")
	ctx, err := svc.RetrieveContext(context.Background(), "kubectl", "debug-pod", 8192)

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

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

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

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

	if ctx.BudgetUsed != 2048 {
		t.Errorf("expected budget used 2048, got %d", ctx.BudgetUsed)
	}
}

func TestServiceGetVault(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/memory/vault" {
			t.Errorf("unexpected path: %s", r.URL.Path)
		}

		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(VaultResponse{
			Project:      "poimen",
			TotalRecords: 100,
			Files: []VaultFile{
				{
					Path:        "docs/guide.md",
					Title:       "Guide",
					Level:       "L1",
					RecordCount: 25,
				},
				{
					Path:        "reference/api.md",
					Title:       "API",
					Level:       "R",
					RecordCount: 75,
				},
			},
		})
	}))
	defer server.Close()

	svc := NewService(server.URL, "test-token", "poimen")
	files, err := svc.GetVault(context.Background())

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

	if len(files) != 2 {
		t.Errorf("expected 2 files, got %d", len(files))
	}

	if files[0].Title != "Guide" {
		t.Errorf("expected title Guide, got %s", files[0].Title)
	}
}

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

	svc := NewService(server.URL, "test-token", "poimen")
	if !svc.IsHealthy(context.Background()) {
		t.Error("expected service to be healthy")
	}
}

func TestServiceUpdateKnowledge(t *testing.T) {
	callCount := 0
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		callCount++
		if r.URL.Path != "/memory/ingest" {
			t.Errorf("unexpected path: %s", r.URL.Path)
		}

		w.WriteHeader(http.StatusCreated)
		json.NewEncoder(w).Encode(IngestResponse{
			ID:          "chunk-123",
			QueueStatus: "pending",
		})
	}))
	defer server.Close()

	svc := NewService(server.URL, "test-token", "poimen")
	record := &KnowledgeRecord{
		ID:      "chunk-123",
		Content: "updated knowledge",
		Level:   "L1",
	}

	id, err := svc.UpdateKnowledge(context.Background(), record)

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

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

	if callCount != 1 {
		t.Errorf("expected 1 call, got %d", callCount)
	}
}
