//go:build e2e

package e2e

import (
	"fmt"
	"net/http/httptest"
	"testing"

	"github.com/pingcap/failpoint"

	"github.com/tidbcloud/AgentTeam/desktop/internal/agent"
	"github.com/tidbcloud/AgentTeam/desktop/internal/operator"
	"github.com/tidbcloud/AgentTeam/desktop/internal/profile"
	"github.com/tidbcloud/AgentTeam/desktop/internal/types"
)

// setupOperatorServer creates a Gin router with dashboard handlers wrapped in
// an httptest.Server and returns an APIOperator that talks to it via HTTP.
func setupOperatorServer(t *testing.T) operator.Operator {
	t.Helper()
	cfgDir := t.TempDir()
	failpoint.Enable("agentteam-config-dir", fmt.Sprintf(`return("%s")`, cfgDir))
	t.Cleanup(func() { failpoint.Disable("agentteam-config-dir") })

	router := newFullRouter(t, profile.Default().Servers())
	server := httptest.NewServer(router)
	t.Cleanup(server.Close)

	return operator.NewAPIOperator(server.URL, "test-api-key")
}

// ---------------------------------------------------------------------------
// Agent e2e via Operator
// ---------------------------------------------------------------------------

func TestOperator_AgentReadOnly(t *testing.T) {
	op := setupOperatorServer(t)

	channel := profile.AgentTeamServer{ID: "agentteam-channel", Enabled: true, Name: "AgentTeam Server"}
	if err := profile.Default().Servers().Add(&channel); err != nil {
		t.Fatalf("seed channel: %v", err)
	}
	if err := profile.Default().Agents().Add(agent.Config{
		ID:      "synced-agent",
		Name:    "Synced Agent",
		Runtime: "opencode",
		Source:  agent.AgentSource{Type: "agentteam", ID: channel.ID},
	}); err != nil {
		t.Fatalf("seed agent: %v", err)
	}

	agents, err := op.Agents().All()
	if err != nil {
		t.Fatalf("Agents().All() error = %v", err)
	}
	if len(agents) != 1 {
		t.Fatalf("Agents().All() count = %d, want 1", len(agents))
	}

	a, ok, err := op.Agents().Get("synced-agent")
	if err != nil || !ok {
		t.Fatalf("Get() error = %v, ok = %v", err, ok)
	}
	if a.Runtime != "opencode" {
		t.Fatalf("Get() Runtime = %q, want %q", a.Runtime, "opencode")
	}
	if a.Source.Type != "agentteam" {
		t.Fatalf("Get() Source.Type = %q, want agentteam", a.Source.Type)
	}
}

// ---------------------------------------------------------------------------
// Channel e2e via Operator
// ---------------------------------------------------------------------------

func TestOperator_ChannelCRUD(t *testing.T) {
	op := setupOperatorServer(t)

	// Add
	ch, err := op.Servers().Add(&profile.AgentTeamServer{
		Name: "Test AgentTeam", AgentID: "agent-1",
		Config: types.RawMessage("server_url: \"http://localhost:8080\"\n"),
	})
	if err != nil {
		t.Fatalf("Servers().Add() error = %v", err)
	}

	chID := ch.ID

	// Get
	ch, ok, err := op.Servers().Get(chID)
	if err != nil || !ok {
		t.Fatalf("Get() error = %v, ok = %v", err, ok)
	}
	if ch.AgentID != "agent-1" {
		t.Fatalf("Get() AgentID = %q, want %q", ch.AgentID, "agent-1")
	}

	// List
	channels, err := op.Servers().All()
	if err != nil {
		t.Fatalf("All() error = %v", err)
	}
	if len(channels) != 1 {
		t.Fatalf("expected 1 channel, got %d", len(channels))
	}

	// Delete
	if err := op.Servers().Delete(chID); err != nil {
		t.Fatalf("Delete() error = %v", err)
	}

	_, ok, err = op.Servers().Get(chID)
	if err != nil || ok {
		t.Fatalf("Get after delete: err = %v, ok = %v", err, ok)
	}
}

// ---------------------------------------------------------------------------
// Skill e2e via Operator
// ---------------------------------------------------------------------------

func TestOperator_SkillGetAndList(t *testing.T) {
	op := setupOperatorServer(t)

	// List empty
	skills, err := op.Skills().All()
	if err != nil {
		t.Fatalf("Skills().All() error = %v", err)
	}
	if len(skills) != 0 {
		t.Fatalf("expected empty list, got %d skills", len(skills))
	}

	// Get not found
	_, ok, err := op.Skills().Get("nonexistent")
	if err != nil {
		t.Fatalf("Get(notfound) error = %v", err)
	}
	if ok {
		t.Fatal("Get(notfound) ok = true, want false")
	}
}

// ---------------------------------------------------------------------------
// Operator type detection
// ---------------------------------------------------------------------------

func TestOperator_IsAPIOperator(t *testing.T) {
	op := setupOperatorServer(t)
	if !operator.IsAPIOperator(op) {
		t.Fatal("expected IsAPIOperator = true for API-based operator")
	}

	apiOp := operator.AsAPIOperator(op)
	if apiOp == nil {
		t.Fatal("AsAPIOperator should not return nil")
	}
	if apiOp.BaseURL() == "" {
		t.Fatal("BaseURL() should not be empty")
	}
}
