package main

import (
	"fmt"
	"git.sch9.ru/new_gate/ms-tester/internal/lib"
	"git.sch9.ru/new_gate/ms-tester/internal/services"
	"git.sch9.ru/new_gate/ms-tester/internal/storage"
	"git.sch9.ru/new_gate/ms-tester/internal/transport"
	sessionv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/session/v1"
	"github.com/ilyakaznacheev/cleanenv"
	_ "github.com/jackc/pgx/v5/stdlib"
	"github.com/jmoiron/sqlx"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	var cfg lib.Config
	err := cleanenv.ReadConfig(".env", &cfg)
	if err != nil {
		panic(fmt.Sprintf("error reading config: %s", err.Error()))
	}

	var logger *zap.Logger
	if cfg.Env == "prod" {
		logger = zap.Must(zap.NewProduction())
	} else if cfg.Env == "dev" {
		logger = zap.Must(zap.NewDevelopment())
	} else {
		panic(fmt.Sprintf(`error reading config: env expected "prod" or "dev", got "%s"`, cfg.Env))
	}

	db, err := sqlx.Connect("pgx", cfg.PostgresDSN)
	if err != nil {
		panic(err)
	}
	defer db.Close()

	//contestStorage := storage.NewContestStorage(db, logger)
	//contestService := services.NewContestService(contestStorage)

	pandocClient := lib.NewPandocClient(&http.Client{}, cfg.Pandoc)

	grpcSessionClient, err := grpc.NewClient(cfg.Auth, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		panic(err)
	}
	sessionClient := sessionv1.NewSessionServiceClient(grpcSessionClient)

	permissionService := services.NewPermissionService()

	problemStorage := storage.NewProblemStorage(db, logger)
	problemService := services.NewProblemService(problemStorage, pandocClient, permissionService)

	userStorage := storage.NewUserStorage(db)
	userService := services.NewUserService(userStorage)

	server := transport.NewTesterServer(problemService, sessionClient, userService, logger)

	lis, err := net.Listen("tcp", cfg.Address)
	if err != nil {
		panic(err)
	}

	go func() {
		if err := server.Start(lis); err != nil {
			logger.Fatal("error starting server", zap.Error(err))
		}
	}()

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, syscall.SIGTERM, syscall.SIGINT)

	<-stop
}
