package main

import (
	"context"
	"embed"
	"errors"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"gitlab.mareshq.com/lab/journal/httpserver"
	"gitlab.mareshq.com/lab/journal/journal"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

//go:embed assets/favicon.ico
var favicon []byte

//go:embed templates/*
var templatesFS embed.FS

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

	logger := log.New(os.Stdout, "", log.LstdFlags)

	db, err := gorm.Open(sqlite.Open("var/local.db"), &gorm.Config{})
	if err != nil {
		logger.Fatalf("failed to connect database: %v", err)
	}

	sqlDB, err := db.DB()
	if err != nil {
		logger.Fatalf("failed to get database: %v", err)
	}

	// graceful shutdown of database connections
	defer func() {
		err = sqlDB.Close()
		if err != nil {
			logger.Fatalf("failed to close database: %v", err)
		}
	}()

	err = db.AutoMigrate(&journal.Entry{})
	if err != nil {
		logger.Fatalf("failed to migrate database: %v\n", err)
	}

	repo := journal.NewRepository(db)
	tr := httpserver.NewTemplateRenderer(templatesFS)

	mux := http.NewServeMux()

	fav := httpserver.NewFavicon(favicon)
	mux.HandleFunc("GET /favicon.ico", fav.FaviconHandler)

	// Journal server is HTTP interface
	journalServer := journal.NewServer(repo, tr, logger)
	journalServer.RegisterRoutes(mux)

	loggingMiddleware := httpserver.NewLoggingMiddleware(logger)

	server := &http.Server{
		Addr:    ":8080",
		Handler: loggingMiddleware.Logging(mux),
	}

	// start the HTTP server in a goroutine
	go func() {
		logger.Printf("Starting HTTP server on %s\n", server.Addr)
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			logger.Fatalf("listen: %s\n", err)
		}
	}()

	<-ctx.Done()
	logger.Println("Received signal, shutting down...")

	ctxShutdown, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := server.Shutdown(ctxShutdown); err != nil && !errors.Is(err, http.ErrServerClosed) {
		logger.Fatalf("HTTP Server forced to shutdown: %v", err)
	}

	logger.Println("HTTP server shut down")
}
