package openai

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

	"github.com/nomadcode/nomadcode-core/internal/model"
)

func TestGenerateCallsResponsesAPI(t *testing.T) {
	var gotPath string
	var gotAuth string
	var gotBody map[string]any

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		gotPath = r.URL.Path
		gotAuth = r.Header.Get("Authorization")
		if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil {
			t.Fatalf("decode request: %v", err)
		}

		w.Header().Set("Content-Type", "application/json")
		_, _ = w.Write([]byte(`{
			"id": "resp_test",
			"model": "qwen3.6:35b-a3b-bf16",
			"output_text": "hello from model",
			"usage": {
				"input_tokens": 3,
				"output_tokens": 4,
				"total_tokens": 7
			}
		}`))
	}))
	defer server.Close()

	client := NewClient(Config{
		BaseURL:     server.URL,
		APIKey:      "test-key",
		Model:       "qwen3.6:35b-a3b-bf16",
		ContextSize: 262144,
	}, nil)

	result, err := client.Generate(context.Background(), model.GenerateInput{
		Input:        "say hello",
		Instructions: "be brief",
		Metadata: map[string]string{
			"task_id": "task-123",
			"source":  "plane",
		},
	})
	if err != nil {
		t.Fatalf("Generate returned error: %v", err)
	}

	if gotPath != "/v1/responses" {
		t.Fatalf("expected /v1/responses, got %q", gotPath)
	}
	if gotAuth != "Bearer test-key" {
		t.Fatalf("expected auth header, got %q", gotAuth)
	}
	if gotBody["model"] != "qwen3.6:35b-a3b-bf16" {
		t.Fatalf("unexpected model: %#v", gotBody["model"])
	}
	if gotBody["input"] != "say hello" {
		t.Fatalf("unexpected input: %#v", gotBody["input"])
	}
	if gotBody["instructions"] != "be brief" {
		t.Fatalf("unexpected instructions: %#v", gotBody["instructions"])
	}
	metadata, ok := gotBody["metadata"].(map[string]any)
	if !ok {
		t.Fatalf("expected metadata object, got %#v", gotBody["metadata"])
	}
	if metadata["task_id"] != "task-123" || metadata["source"] != "plane" {
		t.Fatalf("unexpected metadata: %#v", metadata)
	}
	if _, ok := gotBody["context_size"]; ok {
		t.Fatal("Responses API request must not include unsupported context_size")
	}
	options, ok := gotBody["options"].(map[string]any)
	if !ok {
		t.Fatalf("expected options object, got %#v", gotBody["options"])
	}
	if options["num_ctx"] != float64(262144) {
		t.Fatalf("unexpected options.num_ctx: %#v", options["num_ctx"])
	}
	if result.Text != "hello from model" {
		t.Fatalf("unexpected result text: %q", result.Text)
	}
	if result.Usage.TotalTokens != 7 {
		t.Fatalf("unexpected usage: %#v", result.Usage)
	}
}

func TestGenerateWorkspaceMetadataUsesFlatWorkspacePath(t *testing.T) {
	var gotBody map[string]any

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil {
			t.Fatalf("decode request: %v", err)
		}
		w.Header().Set("Content-Type", "application/json")
		_, _ = w.Write([]byte(`{"id":"r1","model":"m","output_text":"ok","usage":{"total_tokens":1}}`))
	}))
	defer server.Close()

	client := NewClient(Config{BaseURL: server.URL, Model: "m"}, nil)
	_, err := client.Generate(context.Background(), model.GenerateInput{
		Input: "author milestone",
		Metadata: map[string]string{
			"task_id": "task-abc",
			"source":  "plane",
		},
		WorkspaceMetadata: &model.WorkspaceMetadata{
			Path:         "/home/user/workspace/nomadcode/slots/000",
			SourceBranch: "develop",
			Provider:     "plane",
			WorkItemID:   "NOMAD-42",
		},
	})
	if err != nil {
		t.Fatalf("Generate returned error: %v", err)
	}

	metadata, ok := gotBody["metadata"].(map[string]any)
	if !ok {
		t.Fatalf("expected metadata object, got %T: %#v", gotBody["metadata"], gotBody["metadata"])
	}
	if metadata["task_id"] != "task-abc" || metadata["source"] != "plane" {
		t.Fatalf("flat metadata not preserved: %#v", metadata)
	}
	wsPath, ok := metadata["workspace"].(string)
	if !ok {
		t.Fatalf("expected metadata.workspace string, got %T: %#v", metadata["workspace"], metadata["workspace"])
	}
	if wsPath != "/home/user/workspace/nomadcode/slots/000" {
		t.Fatalf("unexpected workspace path: %#v", wsPath)
	}
}

func TestGenerateExtractsOutputContent(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		_, _ = w.Write([]byte(`{
			"id": "resp_test",
			"output": [
				{
					"type": "message",
					"content": [
						{"type": "output_text", "text": "hello "},
						{"type": "output_text", "text": "again"}
					]
				}
			],
			"usage": {
				"prompt_tokens": 2,
				"completion_tokens": 5
			}
		}`))
	}))
	defer server.Close()

	client := NewClient(Config{BaseURL: server.URL, Model: "model-a"}, nil)
	result, err := client.Generate(context.Background(), model.GenerateInput{Input: "say hello"})
	if err != nil {
		t.Fatalf("Generate returned error: %v", err)
	}
	if result.Text != "hello again" {
		t.Fatalf("unexpected result text: %q", result.Text)
	}
	if result.Usage.InputTokens != 2 || result.Usage.OutputTokens != 5 || result.Usage.TotalTokens != 7 {
		t.Fatalf("unexpected usage: %#v", result.Usage)
	}
}

func TestResponsesURL(t *testing.T) {
	tests := map[string]string{
		"http://localhost:11434":              "http://localhost:11434/v1/responses",
		"http://localhost:11434/":             "http://localhost:11434/v1/responses",
		"http://localhost:11434/v1":           "http://localhost:11434/v1/responses",
		"http://localhost:11434/v1/":          "http://localhost:11434/v1/responses",
		"http://localhost:11434/v1/responses": "http://localhost:11434/v1/responses",
	}

	for input, want := range tests {
		got, err := responsesURL(input)
		if err != nil {
			t.Fatalf("responsesURL(%q) returned error: %v", input, err)
		}
		if got != want {
			t.Fatalf("responsesURL(%q) = %q, want %q", input, got, want)
		}
	}
}
