package execution

import (
	"context"
	"errors"
	"testing"
)

func TestFailureCodecRoundTrip(t *testing.T) {
	input := &Failure{
		Code:      FailureCodeQuotaExhausted,
		Message:   "weekly quota exhausted",
		Retryable: true,
		Metadata:  map[string]string{"target": "codex"},
	}

	payload, err := EncodeFailure(input)
	if err != nil {
		t.Fatalf("EncodeFailure() error = %v", err)
	}
	output, err := DecodeFailure(payload)
	if err != nil {
		t.Fatalf("DecodeFailure() error = %v", err)
	}
	if output.Code != input.Code || output.Message != input.Message || output.Retryable != input.Retryable {
		t.Fatalf("round trip = %#v, want %#v", output, input)
	}
	if output.Metadata["target"] != "codex" {
		t.Fatalf("metadata = %#v", output.Metadata)
	}
}

func TestFailureCodecNormalizesUnknownCode(t *testing.T) {
	output, err := DecodeFailure(`{"schema_version":1,"failure":{"code":"future_code","message":"future"}}`)
	if err != nil {
		t.Fatalf("DecodeFailure() error = %v", err)
	}
	if output.Code != FailureCodeUnknown {
		t.Fatalf("Code = %q, want %q", output.Code, FailureCodeUnknown)
	}
	if output.Metadata["original_code"] != "future_code" {
		t.Fatalf("metadata = %#v", output.Metadata)
	}
}

func TestFailureCodecPreservesResponseStalled(t *testing.T) {
	input := &Failure{Code: FailureCodeResponseStalled, Retryable: true, Metadata: map[string]string{"attempt_fence": "confirmed"}}
	payload, err := EncodeFailure(input)
	if err != nil {
		t.Fatalf("EncodeFailure() error = %v", err)
	}
	output, err := DecodeFailure(payload)
	if err != nil {
		t.Fatalf("DecodeFailure() error = %v", err)
	}
	if output.Code != FailureCodeResponseStalled || !output.Retryable || output.Metadata["attempt_fence"] != "confirmed" {
		t.Fatalf("round trip = %#v", output)
	}
}

func TestFailureFromErrorCancellationBoundary(t *testing.T) {
	tests := []struct {
		name      string
		err       error
		code      FailureCode
		retryable bool
	}{
		{name: "runtime cancellation", err: ErrRunCancelled, code: FailureCodeCancelled},
		{name: "context cancellation", err: context.Canceled, code: FailureCodeCancelled},
		{name: "deadline", err: context.DeadlineExceeded, code: FailureCodeDeadlineExceeded, retryable: true},
		{name: "unknown", err: errors.New("provider failed"), code: FailureCodeUnknown},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			failure := FailureFromError(test.err)
			if failure.Code != test.code || failure.Retryable != test.retryable {
				t.Fatalf("FailureFromError() = %#v", failure)
			}
		})
	}
}
