package inbox

import (
	"os"
	"path/filepath"
	"testing"
)

func TestDoneMarksThreadTerminal(t *testing.T) {
	t.Parallel()

	dbPath := filepath.Join(t.TempDir(), "coord.db")
	threadID := seedClaimedThreadForInboxTests(t, dbPath, "leader", "worker-a", "worker-a")

	doneOut := runInboxCommand(
		t,
		"--db", dbPath,
		"--json",
		"done",
		"--agent", "worker-a",
		"--thread", threadID,
		"--summary", "Retry policy implemented",
		"--body", "The HTTP client now retries the selected transient failures.",
	)

	var doneResp map[string]any
	mustDecodeJSON(t, doneOut, &doneResp)
	if status := nestedString(t, doneResp, "data", "thread", "status"); status != "done" {
		t.Fatalf("expected done thread status, got %q", status)
	}
	if kind := nestedString(t, doneResp, "data", "message", "kind"); kind != "result" {
		t.Fatalf("expected result message kind, got %q", kind)
	}
}

func TestDonePersistsResultBodyAndArtifact(t *testing.T) {
	t.Parallel()

	tempDir := t.TempDir()
	dbPath := filepath.Join(tempDir, "coord.db")
	resultPath := filepath.Join(tempDir, "result.md")
	body := "Result from body file."
	if err := os.WriteFile(resultPath, []byte(body), 0o644); err != nil {
		t.Fatalf("write result file: %v", err)
	}

	threadID := seedClaimedThreadForInboxTests(t, dbPath, "leader", "worker-a", "worker-a")

	runInboxCommand(
		t,
		"--db", dbPath,
		"--json",
		"done",
		"--agent", "worker-a",
		"--thread", threadID,
		"--summary", "Retry policy implemented",
		"--body-file", resultPath,
		"--artifact", resultPath,
		"--artifact-kind", "report",
	)

	showOut := runInboxCommand(
		t,
		"--db", dbPath,
		"--json",
		"show",
		"--thread", threadID,
	)
	var showResp map[string]any
	mustDecodeJSON(t, showOut, &showResp)
	lastMessage := lastThreadMessageFromShow(t, showResp)

	if gotBody, _ := lastMessage["body"].(string); gotBody != body {
		t.Fatalf("expected body %q, got %#v", body, lastMessage["body"])
	}
	artifacts, ok := lastMessage["artifacts"].([]any)
	if !ok || len(artifacts) != 1 {
		t.Fatalf("expected one artifact, got %#v", lastMessage["artifacts"])
	}
	artifact, ok := artifacts[0].(map[string]any)
	if !ok {
		t.Fatalf("expected artifact object, got %#v", artifacts[0])
	}
	if gotPath, _ := artifact["path"].(string); gotPath != resultPath {
		t.Fatalf("expected artifact path %q, got %#v", resultPath, artifact["path"])
	}
	if gotKind, _ := artifact["kind"].(string); gotKind != "report" {
		t.Fatalf("expected artifact kind report, got %#v", artifact["kind"])
	}
}

func TestDoneRejectsNonOwner(t *testing.T) {
	t.Parallel()

	dbPath := filepath.Join(t.TempDir(), "coord.db")
	threadID := seedClaimedThreadForInboxTests(t, dbPath, "leader", "worker-a", "worker-a")

	stdout, _, exitCode := executeInboxCommand(
		"--db", dbPath,
		"--json",
		"done",
		"--agent", "worker-b",
		"--thread", threadID,
		"--summary", "Retry policy implemented",
	)
	if exitCode != 20 {
		t.Fatalf("expected exit code 20, got %d with output %s", exitCode, stdout)
	}
	assertErrorJSON(t, stdout, "lease_conflict")
}

func TestDoneRejectsOnTerminalThread(t *testing.T) {
	t.Parallel()

	dbPath := filepath.Join(t.TempDir(), "coord.db")
	threadID := seedClaimedThreadForInboxTests(t, dbPath, "leader", "worker-a", "worker-a")

	runInboxCommand(
		t,
		"--db", dbPath,
		"--json",
		"done",
		"--agent", "worker-a",
		"--thread", threadID,
		"--summary", "Retry policy implemented",
	)

	stdout, _, exitCode := executeInboxCommand(
		"--db", dbPath,
		"--json",
		"done",
		"--agent", "worker-a",
		"--thread", threadID,
		"--summary", "Retry policy implemented",
	)
	if exitCode != 30 {
		t.Fatalf("expected exit code 30, got %d with output %s", exitCode, stdout)
	}
	assertErrorJSON(t, stdout, "invalid_state")
}
