// Error decoding must preserve status and structured causes even for malformed
// responses, which the real daemon E2E suite does not produce.
package daemon

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func TestHTTPFailuresRetainIdentity(t *testing.T) {
	for _, tc := range []struct {
		name, body, code, workspace string
		status                      int
	}{
		{"workspace", `{"code":"workspace_missing","workspace":"/missing","error":"wording can change"}`, "workspace_missing", "/missing", 409},
		{"forbidden", `{"code":"forbidden","error":"access denied"}`, "forbidden", "", 403},
		{"unauthorized", `{"code":"unauthorized","error":"sign in again"}`, "unauthorized", "", 401},
		{"code only", `{"code":"busy"}`, "busy", "", 503},
		{"malformed", `<html>bad gateway</html>`, "", "", 502},
	} {
		t.Run(tc.name, func(t *testing.T) {
			server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(tc.status)
				_, _ = io.WriteString(w, tc.body)
			}))
			defer server.Close()
			// This fixed peer has no discovery directory; authentication errors stay local.
			conn := NewConnection(ConnectionSnapshot{Port: server.Listener.Addr().(*net.TCPAddr).Port}, nil)
			_, requestErr := requestBytes(context.Background(), conn, operation{Name: "read failure", Method: http.MethodGet, Path: "/failure", Policy: readRecovery}, responseLimits{bodyBytes: 50 * 1024 * 1024, errorBytes: 64 * 1024})
			client := NewChatClient(conn, "session")
			_, chatErr := client.GetStatus(context.Background())
			for _, err := range []error{requestErr, chatErr} {
				err = fmt.Errorf("request context: %w", err)
				var apiErr *APIError
				if !errors.As(err, &apiErr) || apiErr.StatusCode != tc.status || apiErr.Code != tc.code {
					t.Fatalf("lost HTTP failure identity: %v", err)
				}
				var workspaceErr *WorkspaceMissingError
				if tc.workspace != "" && (!errors.As(err, &workspaceErr) || workspaceErr.Workspace != tc.workspace) {
					t.Fatalf("lost workspace recovery information: %v", err)
				}
				if strings.Contains(err.Error(), "<html>") {
					t.Fatalf("exposed unstructured response body: %v", err)
				}
			}
		})
	}
}
