package agents

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

	"github.com/enmanuel/agents/internal/config"
	toolmemory "github.com/enmanuel/agents/tools/memorytools"
)

func TestBuildToolRegistry_MinimalConfig(t *testing.T) {
	logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
	cfg := &config.AgentConfig{
		Agent: config.AgentMeta{ID: "test-agent"},
	}
	roomCtx := &toolmemory.RoomContext{}

	reg := buildToolRegistry(cfg, nil, nil, nil, nil, nil, nil, nil, nil, roomCtx, logger)

	// Always-registered tools: current_time, weather, bus_send
	names := reg.Names()
	if len(names) < 3 {
		t.Fatalf("expected at least 3 always-on tools, got %d: %v", len(names), names)
	}
	assertToolRegistered(t, reg, "current_time")
	assertToolRegistered(t, reg, "get_weather")
	assertToolRegistered(t, reg, "bus_send")
}

func TestBuildToolRegistry_HTTPEnabled(t *testing.T) {
	logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
	cfg := &config.AgentConfig{
		Agent: config.AgentMeta{ID: "test-agent"},
		Tools: config.ToolsCfg{
			HTTP: config.HTTPToolCfg{Enabled: true, AllowedDomains: []string{"example.com"}},
		},
	}
	roomCtx := &toolmemory.RoomContext{}

	reg := buildToolRegistry(cfg, nil, nil, nil, nil, nil, nil, nil, nil, roomCtx, logger)

	assertToolRegistered(t, reg, "http_get")
	assertToolRegistered(t, reg, "http_post")
}

func TestBuildToolRegistry_HTTPDisabled(t *testing.T) {
	logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
	cfg := &config.AgentConfig{
		Agent: config.AgentMeta{ID: "test-agent"},
	}
	roomCtx := &toolmemory.RoomContext{}

	reg := buildToolRegistry(cfg, nil, nil, nil, nil, nil, nil, nil, nil, roomCtx, logger)

	assertToolNotRegistered(t, reg, "http_get")
	assertToolNotRegistered(t, reg, "http_post")
}

func TestBuildToolRegistry_FileOpsReadOnly(t *testing.T) {
	logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
	cfg := &config.AgentConfig{
		Agent: config.AgentMeta{ID: "test-agent"},
		Tools: config.ToolsCfg{
			FileOps: config.FileOpsCfg{Enabled: true, ReadOnly: true, AllowedPaths: []string{"/tmp"}},
		},
	}
	roomCtx := &toolmemory.RoomContext{}

	reg := buildToolRegistry(cfg, nil, nil, nil, nil, nil, nil, nil, nil, roomCtx, logger)

	assertToolRegistered(t, reg, "read_file")
	assertToolRegistered(t, reg, "list_directory")
	assertToolNotRegistered(t, reg, "write_file")
	assertToolNotRegistered(t, reg, "append_file")
	assertToolNotRegistered(t, reg, "delete_file")
}

func TestBuildToolRegistry_FileOpsReadWrite(t *testing.T) {
	logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
	cfg := &config.AgentConfig{
		Agent: config.AgentMeta{ID: "test-agent"},
		Tools: config.ToolsCfg{
			FileOps: config.FileOpsCfg{Enabled: true, ReadOnly: false, AllowedPaths: []string{"/tmp"}},
		},
	}
	roomCtx := &toolmemory.RoomContext{}

	reg := buildToolRegistry(cfg, nil, nil, nil, nil, nil, nil, nil, nil, roomCtx, logger)

	assertToolRegistered(t, reg, "read_file")
	assertToolRegistered(t, reg, "list_directory")
	assertToolRegistered(t, reg, "write_file")
	assertToolRegistered(t, reg, "append_file")
	assertToolRegistered(t, reg, "delete_file")
}

func TestBuildToolRegistry_IMDbEnabled(t *testing.T) {
	logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
	cfg := &config.AgentConfig{
		Agent: config.AgentMeta{ID: "test-agent"},
		Tools: config.ToolsCfg{
			IMDb: config.IMDbToolCfg{Enabled: true},
		},
	}
	roomCtx := &toolmemory.RoomContext{}

	reg := buildToolRegistry(cfg, nil, nil, nil, nil, nil, nil, nil, nil, roomCtx, logger)

	assertToolRegistered(t, reg, "imdb_search")
}

func TestBuildToolRegistry_SSHEnabled(t *testing.T) {
	logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
	cfg := &config.AgentConfig{
		Agent: config.AgentMeta{ID: "test-agent"},
		Tools: config.ToolsCfg{
			SSH: config.SSHToolCfg{Enabled: true},
		},
	}
	roomCtx := &toolmemory.RoomContext{}

	// SSH tool requires an executor; passing nil is fine for registration (only used at exec time)
	reg := buildToolRegistry(cfg, nil, nil, nil, nil, nil, nil, nil, nil, roomCtx, logger)

	assertToolRegistered(t, reg, "ssh_command")
}

func TestBuildToolRegistry_ToolCount(t *testing.T) {
	logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))

	// Enable everything that doesn't need external deps
	cfg := &config.AgentConfig{
		Agent: config.AgentMeta{ID: "test-agent"},
		Tools: config.ToolsCfg{
			HTTP:    config.HTTPToolCfg{Enabled: true},
			SSH:     config.SSHToolCfg{Enabled: true},
			FileOps: config.FileOpsCfg{Enabled: true, AllowedPaths: []string{"/tmp"}},
			IMDb:    config.IMDbToolCfg{Enabled: true},
		},
	}
	roomCtx := &toolmemory.RoomContext{}

	reg := buildToolRegistry(cfg, nil, nil, nil, nil, nil, nil, nil, nil, roomCtx, logger)

	// 3 always-on + 2 HTTP + 1 SSH + 5 file + 1 IMDb = 12
	expected := 12
	if got := reg.Len(); got != expected {
		t.Errorf("expected %d tools, got %d: %v", expected, got, reg.Names())
	}
}

// ── Test helpers ────────────────────────────────────────────────────────────

func assertToolRegistered(t *testing.T, reg interface{ Names() []string }, name string) {
	t.Helper()
	for _, n := range reg.Names() {
		if n == name {
			return
		}
	}
	t.Errorf("expected tool %q to be registered, but it was not. Registered: %v", name, reg.Names())
}

func assertToolNotRegistered(t *testing.T, reg interface{ Names() []string }, name string) {
	t.Helper()
	for _, n := range reg.Names() {
		if n == name {
			t.Errorf("expected tool %q NOT to be registered, but it was", name)
			return
		}
	}
}
