package orch

import (
	"bytes"
	"encoding/json"
	"testing"

	inboxcli "ai-workflow-skill/internal/cli/inbox"
)

func runOrchCommand(t *testing.T, args ...string) string {
	t.Helper()

	stdout, stderr, exitCode := executeOrchCommand(args...)
	if exitCode != 0 {
		t.Fatalf("execute orch command %v: exit=%d\nstderr:\n%s\nstdout:\n%s", args, exitCode, stderr, stdout)
	}

	return stdout
}

func executeOrchCommand(args ...string) (string, string, int) {
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	exitCode := Execute(args, &stdout, &stderr)
	return stdout.String(), stderr.String(), exitCode
}

func runInboxCommand(t *testing.T, args ...string) string {
	t.Helper()

	stdout, stderr, exitCode := executeInboxCommand(args...)
	if exitCode != 0 {
		t.Fatalf("execute inbox command %v: exit=%d\nstderr:\n%s\nstdout:\n%s", args, exitCode, stderr, stdout)
	}

	return stdout
}

func executeInboxCommand(args ...string) (string, string, int) {
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	exitCode := inboxcli.Execute(args, &stdout, &stderr)
	return stdout.String(), stderr.String(), exitCode
}

func mustDecodeJSON(t *testing.T, raw string, target any) {
	t.Helper()

	if err := json.Unmarshal([]byte(raw), target); err != nil {
		t.Fatalf("decode json %q: %v", raw, err)
	}
}

func nestedString(t *testing.T, value map[string]any, keys ...string) string {
	t.Helper()

	current := nestedValue(t, value, keys...)
	str, ok := current.(string)
	if !ok {
		t.Fatalf("expected string at %v, got %#v", keys, current)
	}
	return str
}

func nestedValue(t *testing.T, value map[string]any, keys ...string) any {
	t.Helper()

	var current any = value
	for _, key := range keys {
		obj, ok := current.(map[string]any)
		if !ok {
			t.Fatalf("expected object at %q in %v, got %#v", key, keys, current)
		}
		current, ok = obj[key]
		if !ok {
			t.Fatalf("missing key %q in %v", key, keys)
		}
	}
	return current
}

func nestedArray(t *testing.T, value map[string]any, keys ...string) []any {
	t.Helper()

	current := nestedValue(t, value, keys...)
	items, ok := current.([]any)
	if !ok {
		t.Fatalf("expected array at %v, got %#v", keys, current)
	}
	return items
}

func assertErrorJSON(t *testing.T, raw string, expectedCode string) {
	t.Helper()

	var payload map[string]any
	mustDecodeJSON(t, raw, &payload)
	if ok, _ := payload["ok"].(bool); ok {
		t.Fatalf("expected ok=false error payload, got %#v", payload)
	}
	errorValue, ok := payload["error"].(map[string]any)
	if !ok {
		t.Fatalf("expected error object, got %#v", payload["error"])
	}
	if code, _ := errorValue["code"].(string); code != expectedCode {
		t.Fatalf("expected error code %q, got %#v", expectedCode, errorValue["code"])
	}
}
