package main

import (
	"amocrm/cmd/tokens/refresh_wc"
	"amocrm/internal/initialize"
	"amocrm/internal/workers/limiter"
	"amocrm/pkg/amoClient"
	"amocrm/pkg/closer"
	"context"
	"errors"
	"fmt"
	"go.uber.org/zap"
	"os"
	"os/signal"
	"gitea.pena/SQuiz/common/dal"
	"syscall"
	"time"
)

func main() {
	logger, err := zap.NewProduction()
	if err != nil {
		fmt.Printf("Failed to initialize logger: %v\n", err)
		os.Exit(1)
	}

	logger = logger.Named("REFRESH_WC")

	config, err := initialize.LoadConfig()
	if err != nil {
		logger.Fatal("Failed to load config", zap.Error(err))
	}

	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	if err = run(ctx, logger, *config); err != nil {
		logger.Fatal("App exited with error", zap.Error(err))
	}
}

func run(ctx context.Context, logger *zap.Logger, cfg initialize.Config) error {
	defer func() {
		if r := recover(); r != nil {
			logger.Error("Recovered in app from a panic", zap.Any("error", r))
		}
	}()

	shutdownGroup := closer.NewCloserGroup()

	amoRepo, err := dal.NewAmoDal(ctx, cfg.PostgresCredentials)
	if err != nil {
		logger.Error("error init amo repo", zap.Error(err))
		return err
	}

	rateLimiter := limiter.NewRateLimiter(ctx, 6, 1500*time.Millisecond)

	amoCl := amoClient.NewAmoClient(amoClient.AmoDeps{
		Logger:            logger,
		RedirectionURL:    cfg.ReturnURL,
		IntegrationID:     cfg.IntegrationID,
		IntegrationSecret: cfg.IntegrationSecret,
		RateLimiter:       rateLimiter,
	})

	refreshWC := refresh_wc.NewRefreshWC(refresh_wc.Deps{
		Logger:    logger,
		AmoClient: amoCl,
		Repo:      amoRepo,
	})

	go refreshWC.Start(ctx)

	shutdownGroup.Add(closer.CloserFunc(amoRepo.Close))
	shutdownGroup.Add(closer.CloserFunc(rateLimiter.Stop))
	shutdownGroup.Add(closer.CloserFunc(refreshWC.Stop))

	<-ctx.Done()

	timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer timeoutCancel()
	if err := shutdownGroup.Call(timeoutCtx); err != nil {
		if errors.Is(err, context.DeadlineExceeded) {
			logger.Error("Shutdown timed out", zap.Error(err))
		} else {
			logger.Error("Failed to shutdown services gracefully", zap.Error(err))
		}
		return err
	}

	logger.Info("Application has stopped")
	return nil
}
