package mongodb

import (
	"context"
	"fmt"
	"github.com/sony/gobreaker/v2"
	"golang.source-fellows.com/training-fellow/booking/internal"
	"golang.source-fellows.com/training-fellow/booking/internal/model"
	"time"
)

type CircuitBreakerProxy struct {
	wrapped          internal.TrainingStore
	dbCircuitBreaker *gobreaker.CircuitBreaker[any]
}

func NewCircuitBreakerProxy(wrapped internal.TrainingStore, informer internal.StateInformer) *CircuitBreakerProxy {

	settings := gobreaker.Settings{
		Name:        "",
		MaxRequests: 1,
		Interval:    30 * time.Second,
		Timeout:     15 * time.Second,
		ReadyToTrip: func(counts gobreaker.Counts) bool {
			return true
		},
		OnStateChange: func(name string, from gobreaker.State, to gobreaker.State) {
			fmt.Println(name, from, to)
			switch to {
			case gobreaker.StateClosed:
				informer.InformAboutState("db", "closed")
			case gobreaker.StateHalfOpen:
				informer.InformAboutState("db", "closed")
			case gobreaker.StateOpen:
				informer.InformAboutState("db", "open")
				time.AfterFunc(5*time.Second, func() {
					informer.InformAboutState("db", "closed")
				})
			}
		},
		IsSuccessful: nil,
	}
	cb := gobreaker.NewCircuitBreaker[any](settings)
	return &CircuitBreakerProxy{wrapped: wrapped, dbCircuitBreaker: cb}
}

func (c *CircuitBreakerProxy) AddNewTraining(ctx context.Context, training *model.Training) error {

	_, err := c.dbCircuitBreaker.Execute(func() (any, error) {
		err := c.wrapped.AddNewTraining(ctx, training)
		return "", err
	})

	return err

}

func (c *CircuitBreakerProxy) FindTrainings(ctx context.Context) ([]*model.Training, error) {

	trainings, err := c.dbCircuitBreaker.Execute(func() (any, error) {
		trainings, err := c.wrapped.FindTrainings(ctx)
		return trainings, err
	})

	return trainings.([]*model.Training), err
}
