package main

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

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	pgdriver "gorm.io/driver/postgres"
	"gorm.io/gorm"
	gormlogger "gorm.io/gorm/logger"

	"github.com/genex/translate-service/internal/application/service"
	pgrepo "github.com/genex/translate-service/internal/infrastructure/postgres"
	"github.com/genex/translate-service/internal/interface/http/handler"
)

func main() {
	logger, _ := zap.NewProduction()
	defer logger.Sync()

	port := os.Getenv("PORT")
	if port == "" {
		port = "3007"
	}

	// ── Infrastructure layer ────────────────────────────────────────────
	db := mustInitDB(logger)

	addressMappingRepo := pgrepo.NewPostgresAddressMappingRepository(db)

	// ── Application layer ───────────────────────────────────────────────
	svc := service.NewTranslateService(addressMappingRepo)

	// ── Interface layer (HTTP) ──────────────────────────────────────────
	h := handler.NewTranslateHandler(svc)

	r := gin.New()
	r.Use(gin.Recovery())

	// Health checks
	r.GET("/health", func(c *gin.Context) {
		c.JSON(200, gin.H{"status": "ok", "service": "translate-service"})
	})
	r.GET("/health/ready", func(c *gin.Context) { c.JSON(200, gin.H{"status": "ready"}) })
	r.GET("/health/live", func(c *gin.Context) { c.JSON(200, gin.H{"status": "alive"}) })

	// API routes
	api := r.Group("/api/v1/translate")
	api.POST("/mappings", h.CreateMapping)
	api.GET("/resolve", h.Resolve)
	api.GET("/user/:userId", h.GetByUser)

	server := &http.Server{Addr: ":" + port, Handler: r, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second}

	go func() {
		logger.Info("Translate Service starting", zap.String("port", port))
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			logger.Fatal("Failed", zap.Error(err))
		}
	}()

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

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	server.Shutdown(ctx)
	logger.Info("Translate Service stopped")
}

func mustInitDB(logger *zap.Logger) *gorm.DB {
	host := getEnv("DB_HOST", "localhost")
	dbPort := getEnv("DB_PORT", "5432")
	user := getEnv("DB_USERNAME", "genex")
	pass := getEnv("DB_PASSWORD", "genex_dev_password")
	name := getEnv("DB_NAME", "genex")

	dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
		host, dbPort, user, pass, name)

	db, err := gorm.Open(pgdriver.Open(dsn), &gorm.Config{
		Logger: gormlogger.Default.LogMode(gormlogger.Warn),
	})
	if err != nil {
		logger.Fatal("Failed to connect to PostgreSQL", zap.Error(err))
	}

	sqlDB, _ := db.DB()
	sqlDB.SetMaxOpenConns(20)
	sqlDB.SetMaxIdleConns(5)
	sqlDB.SetConnMaxLifetime(30 * time.Minute)

	logger.Info("PostgreSQL connected", zap.String("host", host), zap.String("db", name))
	return db
}

func getEnv(key, fallback string) string {
	if v := os.Getenv(key); v != "" {
		return v
	}
	return fallback
}
