package command

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/spf13/cobra"
	"gopkg.in/yaml.v3"

	paymentapp "git.gocasts.ir/ebhomengo/niki/paymentapp"
	"git.gocasts.ir/ebhomengo/niki/pkg/database"
)

var configPath string

var serveCmd = &cobra.Command{
	Use:   "serve",
	Short: "start payment service",
	RunE:  startServer,
}

func init() {
	serveCmd.Flags().StringVar(
		&configPath,
		"config",
		"deploy/payment/development/config.yaml",
		"config file path",
	)

	rootCmd.AddCommand(serveCmd)
}

func startServer(cmd *cobra.Command, args []string) error {

	// -------------------------
	// load config
	// -------------------------
	//TODO --chage to Loader
	data, err := os.ReadFile(configPath)
	if err != nil {
		return fmt.Errorf("🚩 read config error: %w", err)
	}

	var cfg paymentapp.Config

	if err := yaml.Unmarshal(data, &cfg); err != nil {
		return fmt.Errorf("🚩 parse config error: %w", err)
	}

	// -------------------------
	// connect database
	// -------------------------

	dbConn, err := database.Connect(database.Config{
		Port:            cfg.Postgres.Port,
		Host:            cfg.Postgres.Host,
		Username:        cfg.Postgres.User,
		DBName:          cfg.Postgres.DbName,
		Password:        cfg.Postgres.Password,
		Driver:          cfg.Postgres.Driver,
		SSLMode:         cfg.Postgres.SSLMode,
		MaxIdleConns:    cfg.Postgres.MaxIdleConns,
		MaxOpenConns:    cfg.Postgres.MaxOpenConns,
		ConnMaxLifetime: cfg.Postgres.ConnMaxLifetime,
	})
	if err != nil {
		return err
	}
	defer database.Close(dbConn.DB)

	// -------------------------
	// context
	// -------------------------

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// -------------------------
	// setup app
	// -------------------------

	app, err := paymentapp.Setup(ctx, cfg, dbConn)
	if err != nil {
		return err
	}

	// -------------------------
	// start server
	// -------------------------

	go func() {
		if err := app.Start(); err != nil {
			fmt.Println("🚩 server error:", err)
			cancel()
		}
	}()

	fmt.Println("payment service started 🏃‍➡️")

	// -------------------------
	// shutdown
	// -------------------------

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

	<-sigChan

	fmt.Println("shutting down 🥱...")

	shutdownCtx, shutdownCancel := context.WithTimeout(
		context.Background(),
		10*time.Second,
	)
	defer shutdownCancel()

	return app.Stop(shutdownCtx)
}
