package common

import (
	"context"
	"fmt"

	"github.com/certusone/wormhole/node/pkg/supervisor"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
)

var (
	ScissorsErrors = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "scissor_errors_caught",
			Help: "Total number of unhandled errors caught",
		}, []string{"scissors", "name"})
)

// Start a go routine with recovering from any panic by sending an error to a error channel
func RunWithScissors(ctx context.Context, errC chan error, name string, runnable supervisor.Runnable) {
	go func() {
		defer func() {
			if r := recover(); r != nil {
				switch x := r.(type) {
				case error:
					errC <- fmt.Errorf("%s: %w", name, x)
				default:
					errC <- fmt.Errorf("%s: %v", name, x)
				}
				ScissorsErrors.WithLabelValues("scissors", name).Inc()

			}
		}()
		err := runnable(ctx)
		if err != nil {
			errC <- err
		}
	}()
}

func WrapWithScissors(runnable supervisor.Runnable, name string) supervisor.Runnable {
	return func(ctx context.Context) (result error) {
		defer func() {
			if r := recover(); r != nil {
				switch x := r.(type) {
				case error:
					result = fmt.Errorf("%s: %w", name, x)
				default:
					result = fmt.Errorf("%s: %v", name, x)
				}
				ScissorsErrors.WithLabelValues("scissors", name).Inc()
			}
		}()

		return runnable(ctx)
	}
}
