// Copyright 2026 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later

package plugin

import (
	"errors"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// StatusCode walks the wrap chain and returns the first gRPC status code,
// or codes.Unknown if none is present.
func StatusCode(err error) codes.Code {
	if err == nil {
		return codes.OK
	}
	for cur := err; cur != nil; cur = errors.Unwrap(cur) {
		if st, ok := status.FromError(cur); ok {
			return st.Code()
		}
	}
	return codes.Unknown
}

// IsRetryable reports whether err is worth retrying against the same plugin.
// ExecError is never retryable; it carries an exit code from user code.
func IsRetryable(err error) bool {
	if err == nil {
		return false
	}
	var execErr *ExecError
	if errors.As(err, &execErr) {
		return false
	}
	switch StatusCode(err) {
	case codes.Unavailable, codes.DeadlineExceeded, codes.Aborted:
		return true
	default:
		return false
	}
}
