package main

import (
	"context"
	"github.com/kelseyhightower/envconfig"
	"golang.source-fellows.com/training-fellow/booking/internal"
	"golang.source-fellows.com/training-fellow/booking/internal/inbound/http"
	"golang.source-fellows.com/training-fellow/booking/internal/inbound/nats"
	"golang.source-fellows.com/training-fellow/booking/internal/mongodb"
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

type ApplicationConfig struct {
	HTTPConfig  http.Config
	MongoConfig mongodb.Config
	NatsConfig  nats.Config
}

func main() {

	log.Println("Booking app")
	ctx := context.Background()
	serverCtx, cancel := context.WithCancel(ctx)
	defer cancel()

	applConfig := &ApplicationConfig{}
	err := envconfig.Process("", applConfig)
	if err != nil {
		log.Fatal(err)
	}

	stateService := internal.NewStateService()
	stateService.RegisterListener([]string{"db"}, http.StateListener{})

	trainingStorage := mongodb.NewTrainingStorage(applConfig.MongoConfig)
	cbTrainingStorage := mongodb.NewCircuitBreakerProxy(trainingStorage, stateService)
	trainingService := internal.NewTrainingListingService(cbTrainingStorage)

	wg := sync.WaitGroup{}
	wg.Add(2)

	go func() {
		defer wg.Done()
		for {
			log.Println("going to start nats listener...")
			select {
			case <-serverCtx.Done():
				return
			default:
				listener := nats.NewTrainingListener(applConfig.NatsConfig, cbTrainingStorage)
				err := listener.ListenForNewTrainings(serverCtx)
				if err == nil {
					log.Println("nats.io listener stopped")
					return
				}
			}
			time.Sleep(1 * time.Second)
		}
	}()

	go func() {
		defer wg.Done()
		for {
			select {
			case <-serverCtx.Done():
				return
			default:
				err := http.StartServer(serverCtx, applConfig.HTTPConfig, trainingService)
				if err == nil {
					log.Println("http server stopped")
					return
				}
			}
			time.Sleep(1 * time.Second)
		}
	}()

	go func() {
		quit := make(chan os.Signal, 1)
		signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
		<-quit
		cancel()
	}()

	wg.Wait()

}
