package cli

import (
	"bytes"
	"errors"
	"strings"
	"testing"

	"banger/internal/rpc"
)

// TestTranslateRPCError pins the user-facing error rendering for
// every code the daemon emits today plus the catch-all unknown-code
// path. Buffer is non-TTY so style helpers no-op and assertions
// stay readable.
func TestTranslateRPCError(t *testing.T) {
	var buf bytes.Buffer
	cases := []struct {
		name   string
		code   string
		msg    string
		opID   string
		expect string
	}{
		{"operation_failed strips code", "operation_failed", "vm running", "", "vm running"},
		{"empty code drops prefix", "", "raw boom", "", "raw boom"},
		{"not_found", "not_found", `vm "x" not found`, "", `not found: vm "x" not found`},
		{"not_running", "not_running", "vm is not running", "", "not running: vm is not running"},
		{"already_exists", "already_exists", "image foo", "", "already exists: image foo"},
		{"bad_request", "bad_request", "missing rootfs", "", "bad request: missing rootfs"},
		{"bad_params", "bad_params", "invalid tap name", "", "bad request: invalid tap name"},
		{"bad_version", "bad_version", "unsupported version 99", "", "version mismatch: unsupported version 99"},
		{"unauthorized", "unauthorized", "uid 1000 not allowed", "", "unauthorized: uid 1000 not allowed"},
		{"unknown_method", "unknown_method", "no.such.method", "", "unknown method: no.such.method"},
		{"unknown code falls through", "weird_new_code", "boom", "", "weird_new_code: boom"},
		{"op_id appended in parens", "operation_failed", "boom", "op-deadbeef00ff", "boom (op-deadbeef00ff)"},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			err := &rpc.ErrorResponse{Code: tc.code, Message: tc.msg, OpID: tc.opID}
			got := translateRPCError(&buf, err)
			if got != tc.expect {
				t.Errorf("got %q, want %q", got, tc.expect)
			}
		})
	}
}

// TestTranslateRPCErrorPassesThroughNonRPCErrors covers the dial
// failure / decode failure paths where rpc.Call returns a plain Go
// error rather than *rpc.ErrorResponse. The translator must not
// hide the original message — that's the only signal an operator
// has when the daemon is down.
func TestTranslateRPCErrorPassesThroughNonRPCErrors(t *testing.T) {
	var buf bytes.Buffer
	got := translateRPCError(&buf, errors.New("dial unix /run/banger/bangerd.sock: connect: no such file or directory"))
	if !strings.Contains(got, "no such file or directory") {
		t.Fatalf("plain error lost: got %q", got)
	}
}
