//go:build e2e

package task

import (
	"context"
	"testing"
	"time"

	"github.com/tidbcloud/AgentTeam/e2e/assertions"
	"github.com/tidbcloud/AgentTeam/e2e/client"
	"github.com/tidbcloud/AgentTeam/e2e/testkit"
)

func TestCreateChannelTask(t *testing.T) {
	sc := testkit.NewSingleUserScenario(t)

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	allChannel := testkit.RequireAllChannel(t, sc.API)
	title := testkit.UniqueMessageText("ship-feature")

	created, status, raw, err := sc.API.CreateChannelTasks(ctx, allChannel.ID, title)
	if err != nil {
		t.Fatalf("create channel task: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)
	if len(created.Tasks) != 1 {
		t.Fatalf("expected one created task, got %d", len(created.Tasks))
	}
	task := created.Tasks[0]
	if task.Title != title || task.Status == "" || task.ID == "" {
		t.Fatalf("unexpected created task: %+v", task)
	}
	if task.Status != "todo" {
		t.Fatalf("expected new task to start in todo status, got=%s", task.Status)
	}
	t.Logf("created task: id=%s number=%d status=%s", task.ID, task.TaskNumber, task.Status)

	channelPage, status, raw, err := sc.API.ListChannelTasks(ctx, allChannel.ID)
	if err != nil {
		t.Fatalf("list channel tasks: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)
	if !taskPageContains(channelPage, task.ID) {
		t.Fatalf("created task %s missing from channel task list", task.ID)
	}

	workspacePage, status, raw, err := sc.API.ListWorkspaceTasks(ctx)
	if err != nil {
		t.Fatalf("list workspace tasks: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)
	if !taskPageContains(workspacePage, task.ID) {
		t.Fatalf("created task %s missing from workspace task list", task.ID)
	}
	t.Logf("task visible in channel and workspace lists")
}

func TestCreateMultipleChannelTasks(t *testing.T) {
	sc := testkit.NewSingleUserScenario(t)

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	allChannel := testkit.RequireAllChannel(t, sc.API)
	titleA := testkit.UniqueMessageText("task-a")
	titleB := testkit.UniqueMessageText("task-b")

	created, status, raw, err := sc.API.CreateChannelTasks(ctx, allChannel.ID, titleA, titleB)
	if err != nil {
		t.Fatalf("create multiple channel tasks: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)
	if len(created.Tasks) != 2 {
		t.Fatalf("expected two created tasks, got %d", len(created.Tasks))
	}

	ids := map[string]bool{
		created.Tasks[0].ID: true,
		created.Tasks[1].ID: true,
	}
	if created.Tasks[0].ID == "" || created.Tasks[1].ID == "" {
		t.Fatalf("expected non-empty task ids: %+v", created)
	}

	workspacePage, status, raw, err := sc.API.ListWorkspaceTasks(ctx)
	if err != nil {
		t.Fatalf("list workspace tasks: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)

	var found int
	for _, task := range workspacePage.Tasks {
		if ids[task.ID] {
			found++
		}
	}
	if found != 2 {
		t.Fatalf("expected both created tasks in workspace list, found=%d", found)
	}
	t.Logf("multiple task creation passed: taskIds=%s,%s", created.Tasks[0].ID, created.Tasks[1].ID)
}

func TestTaskClaimUnclaimConsistency(t *testing.T) {
	sc := testkit.NewSingleUserScenario(t)

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	allChannel := testkit.RequireAllChannel(t, sc.API)
	created, status, raw, err := sc.API.CreateChannelTasks(ctx, allChannel.ID, testkit.UniqueMessageText("claim-unclaim"))
	if err != nil {
		t.Fatalf("create task: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)
	taskID := created.Tasks[0].ID

	claim, status, raw, err := sc.API.ClaimTask(ctx, taskID)
	if err != nil {
		t.Fatalf("claim task: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)
	if claim.Task.ID != taskID || claim.Task.Status != "todo" {
		t.Fatalf("unexpected claim result: %+v", claim.Task)
	}

	unclaim, status, raw, err := sc.API.UnclaimTask(ctx, taskID)
	if err != nil {
		t.Fatalf("unclaim task: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)
	if unclaim.Task.ID != taskID || unclaim.Task.Status != "todo" {
		t.Fatalf("unexpected unclaim result: %+v", unclaim.Task)
	}
	t.Logf("task claim/unclaim consistency passed: task=%s", taskID)
}

func TestTaskStatusConsistentAcrossWorkspaceListAndDetail(t *testing.T) {
	sc := testkit.NewSingleUserScenario(t)

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	allChannel := testkit.RequireAllChannel(t, sc.API)
	created, status, raw, err := sc.API.CreateChannelTasks(ctx, allChannel.ID, testkit.UniqueMessageText("status-consistency"))
	if err != nil {
		t.Fatalf("create task: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)
	taskID := created.Tasks[0].ID

	detail, status, raw, err := sc.API.GetTaskDetail(ctx, taskID)
	if err != nil {
		t.Fatalf("get task detail: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)
	if detail.Detail.Task.Status != "todo" {
		t.Fatalf("expected todo from detail response, got=%+v", detail.Detail.Task)
	}

	workspacePage, status, raw, err := sc.API.ListWorkspaceTasks(ctx)
	if err != nil {
		t.Fatalf("list workspace tasks: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)
	workspaceTask, ok := findTaskByID(workspacePage, taskID)
	if !ok {
		t.Fatalf("task %s missing in workspace list", taskID)
	}
	if workspaceTask.Status != "todo" {
		t.Fatalf("expected todo from workspace list, got=%+v", workspaceTask)
	}

	channelPage, status, raw, err := sc.API.ListChannelTasks(ctx, allChannel.ID)
	if err != nil {
		t.Fatalf("list channel tasks: %v", err)
	}
	assertions.RequireStatus(t, status, 200, raw)
	listTask, ok := findTaskByID(channelPage, taskID)
	if !ok {
		t.Fatalf("task %s missing in channel list", taskID)
	}
	if listTask.Status != "todo" {
		t.Fatalf("expected todo from channel list, got=%+v", listTask)
	}

	if created.Tasks[0].Status != detail.Detail.Task.Status || created.Tasks[0].Status != workspaceTask.Status || created.Tasks[0].Status != listTask.Status {
		t.Fatalf("status mismatch: create=%s detail=%s workspace=%s channel=%s", created.Tasks[0].Status, detail.Detail.Task.Status, workspaceTask.Status, listTask.Status)
	}
	t.Logf("task status consistent across create/detail/workspace/channel: task=%s", taskID)
}

func taskPageContains(page client.TaskPage, id string) bool {
	for _, task := range page.Tasks {
		if task.ID == id {
			return true
		}
	}
	return false
}

func findTaskByID(page client.TaskPage, id string) (client.Task, bool) {
	for _, task := range page.Tasks {
		if task.ID == id {
			return task, true
		}
	}
	return client.Task{}, false
}
