package llm

import (
	"context"
	"log/slog"
	"os"
	"testing"

	"code.chimeric.al/chimerical/odidere/internal/config"
)

// testURL returns the LLM endpoint for integration tests.
// Set ODIDERE_LLM_TEST_URL to enable; tests skip if empty.
func testURL(t *testing.T) string {
	t.Helper()
	url := os.Getenv("ODIDERE_LLM_TEST_URL")
	if url == "" {
		t.Skip("ODIDERE_LLM_TEST_URL not set")
	}
	return url
}

// testKey returns the API key for integration tests.
// Reads ODIDERE_LLM_TEST_KEY; empty string is valid (no auth).
func testKey(t *testing.T) string {
	t.Helper()
	return os.Getenv("ODIDERE_LLM_TEST_KEY")
}

// testModel returns the model ID for integration tests.
// Reads ODIDERE_LLM_TEST_MODEL; defaults to "test" if empty.
func testModel(t *testing.T) string {
	t.Helper()
	model := os.Getenv("ODIDERE_LLM_TEST_MODEL")
	if model == "" {
		return "test"
	}
	return model
}

func TestIntegration_ListModels(t *testing.T) {
	_ = testURL(t)
	cfg := Config{
		URL:     testURL(t),
		Key:     testKey(t),
		Timeout: "30s",
	}
	client, err := NewClient(cfg, nil, slog.Default())
	if err != nil {
		t.Fatalf("NewClient: %v", err)
	}

	models, err := client.ListModels(context.Background())
	if err != nil {
		t.Fatalf("ListModels: %v", err)
	}
	if len(models) == 0 {
		t.Error("expected at least one model")
	}
	for _, m := range models {
		if m.ID == "" {
			t.Error("model has empty ID")
		}
	}
}

func TestIntegration_Completions(t *testing.T) {
	_ = testURL(t)
	cfg := Config{
		URL:     testURL(t),
		Key:     testKey(t),
		Timeout: "60s",
	}
	client, err := NewClient(cfg, nil, slog.Default())
	if err != nil {
		t.Fatalf("NewClient: %v", err)
	}

	res, err := client.Completions(
		context.Background(), CompletionsParams{
			Model:         testModel(t),
			SystemMessage: "",
			MaxIterations: 0,
			Messages: []Message{{
				Role: RoleUser,
				ContentParts: []ContentPart{{
					Type: "text",
					Text: "Say hello in three words.",
				}},
			}},
		},
	)
	if err != nil {
		t.Fatalf("Completions: %v", err)
	}
	if len(res.Messages) == 0 {
		t.Fatal("expected at least one message")
	}
	text := res.Messages[len(res.Messages)-1].Text()
	if text == "" {
		t.Error("final message has no text")
	}
}

func TestIntegration_CompletionsStream(t *testing.T) {
	_ = testURL(t)
	cfg := Config{
		URL:     testURL(t),
		Key:     testKey(t),
		Timeout: "60s",
	}
	client, err := NewClient(cfg, nil, slog.Default())
	if err != nil {
		t.Fatalf("NewClient: %v", err)
	}

	events := make(chan StreamEvent)
	errCh := make(chan error, 1)
	go func() {
		errCh <- client.CompletionsStream(
			context.Background(), CompletionsParams{
				Model:         testModel(t),
				SystemMessage: "",
				MaxIterations: 0,
				Messages: []Message{{
					Role: RoleUser,
					ContentParts: []ContentPart{{
						Type: "text",
						Text: "Say hello in three words.",
					}},
				}},
			}, events,
		)
	}()

	var messages []Message
	for evt := range events {
		messages = append(messages, evt.Message)
	}
	if err := <-errCh; err != nil {
		t.Fatalf("CompletionsStream: %v", err)
	}
	if len(messages) == 0 {
		t.Fatal("expected at least one message")
	}
	text := messages[len(messages)-1].Text()
	if text == "" {
		t.Error("final message has no text")
	}
}

func TestIntegration_ToolCalling(t *testing.T) {
	_ = testURL(t)

	// Build a minimal tool registry with a single echo tool.
	reg, err := NewRegistry([]config.ToolConfig{
		{
			Name:        "echo",
			Description: "Echo back the input string",
			Command:     "echo",
			Arguments:   []string{"{{.input}}"},
			Parameters: map[string]any{
				"type": "object",
				"properties": map[string]any{
					"input": map[string]any{"type": "string"},
				},
				"required": []string{"input"},
			},
		},
	})
	if err != nil {
		t.Fatalf("NewRegistry: %v", err)
	}

	cfg := Config{
		URL:     testURL(t),
		Key:     testKey(t),
		Timeout: "60s",
	}
	client, err := NewClient(cfg, reg, slog.Default())
	if err != nil {
		t.Fatalf("NewClient: %v", err)
	}

	res, err := client.Completions(
		context.Background(), CompletionsParams{
			Model:         testModel(t),
			SystemMessage: "",
			MaxIterations: 10,
			Messages: []Message{{
				Role: RoleUser,
				ContentParts: []ContentPart{{
					Type: "text",
					Text: "Use the echo tool to say 'hello'",
				}},
			}},
		},
	)
	if err != nil {
		t.Fatalf("Completions: %v", err)
	}
	if len(res.Messages) == 0 {
		t.Fatal("expected at least one message")
	}
	// The final message should be a non-tool-call assistant message.
	final := res.Messages[len(res.Messages)-1]
	if len(final.ToolCalls) > 0 {
		t.Error("final message still has tool calls")
	}
}
