package orchestrator_test

import (
	"context"
	"path/filepath"
	"testing"
	"time"

	"github.com/flothus/tmux-xterm-research/server-go/internal/harness/envelope"
	"github.com/flothus/tmux-xterm-research/server-go/internal/harness/event"
	"github.com/flothus/tmux-xterm-research/server-go/internal/harness/orchestrator"
	"github.com/flothus/tmux-xterm-research/server-go/internal/harness/store"
	"github.com/flothus/tmux-xterm-research/server-go/internal/harness/transport"
)

// TestClarificationRoundTripClosesLoop is the C2 regression test. The brief:
// "an agent asks for feedback in the output but there is no mechanism to pass
// it up or into the loop, so the thing dies right there." After RespondToClarification
// is added, that hanging chain must close: user's reply lands in the asking
// worker's inbox as a TypeAnswer, and the user_notifications row is marked
// delivered so the dashboard knows the question has been answered.
func TestClarificationRoundTripClosesLoop(t *testing.T) {
	tmp := t.TempDir()
	st, err := store.Open(filepath.Join(tmp, "harness.db"))
	if err != nil {
		t.Fatal(err)
	}
	defer st.Close()
	bus := event.NewBus(st)
	q := transport.New(st, bus)
	orch := orchestrator.New(st, bus)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	_ = orch.CreateRun(ctx, "run-clar", "clarification round-trip")
	for _, id := range []string{"master", "worker-1"} {
		_, _ = st.DB().Exec(`INSERT INTO agents(id, run_id, status, spawned_at, heartbeat_at) VALUES(?,'run-clar','running',?,?)`,
			id, store.FmtTime(store.Now()), store.FmtTime(store.Now()))
	}

	now := store.FmtTime(store.Now())
	// Task is in awaiting_clarification — worker emitted clarify and parked.
	_, _ = st.DB().Exec(`INSERT INTO tasks(id, run_id, owner_agent_id, title, state, attempts, created_at, updated_at) VALUES('t-c','run-clar','worker-1','do thing','awaiting_clarification',0,?,?)`, now, now)
	_, _ = st.DB().Exec(`UPDATE runs SET root_task_id='t-c' WHERE id='run-clar'`)
	// Master had written the question to user_notifications.
	_, _ = st.DB().Exec(`INSERT INTO user_notifications(run_id, task_id, kind, payload, created_at) VALUES('run-clar','t-c','clarification','do you want approach A or B?',?)`, now)

	master := orchestrator.NewMaster(orch, q, nil, "run-clar")

	// User's reply comes back through the master.
	if err := master.RespondToClarification(ctx, "t-c", "use approach B because it preserves history"); err != nil {
		t.Fatalf("RespondToClarification: %v", err)
	}

	// 1. Worker must have an Answer envelope addressed to it.
	got, err := q.Receive(ctx, "worker-1")
	if err != nil {
		t.Fatal(err)
	}
	if got == nil {
		t.Fatalf("worker received no clarification answer — round-trip still broken")
	}
	if got.Type != envelope.TypeAnswer {
		t.Errorf("envelope type = %s, want %s", got.Type, envelope.TypeAnswer)
	}
	if got.TaskID != "t-c" {
		t.Errorf("task_id = %s, want t-c", got.TaskID)
	}
	if got.Payload.Intent == "" || got.Payload.Intent != "use approach B because it preserves history" {
		t.Errorf("answer payload = %q, expected user reply text", got.Payload.Intent)
	}

	// 2. user_notifications row should be marked delivered so the dashboard
	// stops surfacing it as a pending question.
	var delivered int
	_ = st.DB().QueryRow(`SELECT delivered FROM user_notifications WHERE run_id='run-clar' AND task_id='t-c' AND kind='clarification'`).Scan(&delivered)
	if delivered != 1 {
		t.Errorf("user_notifications.delivered = %d, want 1 — answered question still shown as pending", delivered)
	}
}
