package main

import (
	"business-engine/internal/config"
	"business-engine/internal/database"
	"business-engine/internal/payroll"
	"context"
	"log/slog"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/jackc/pgx/v5/pgxpool"
)

// Server contains all dependencies of the application
type Server struct {
	config *config.Config
	logger *slog.Logger
	db     *pgxpool.Pool
	router *http.ServeMux
}

// NewServer constructs a new server
func NewServer(cfg *config.Config, logger *slog.Logger) (*Server, error) {
	dbpool, err := pgxpool.New(context.Background(), cfg.DatabaseURL)
	if err != nil {
		logger.Error("failed to connect to database", "error", err)
		os.Exit(1)
	}

	server := &Server{
		config: cfg,
		logger: logger,
		db:     dbpool,
		router: http.NewServeMux(),
	}

	server.setupRoutes()

	return server, nil
}

// setupRoutes initializes all routes and handlers
func (s *Server) setupRoutes() {
	employeeRepo := database.New(s.db)
	employeeService := payroll.NewService(employeeRepo, s.logger)
	employeeHandler := payroll.NewEmployeeHandler(*employeeService, s.logger)

	s.router.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
	})

	s.router.HandleFunc("GET /api/v1/employees", employeeHandler.ListEmployees)

	s.router.HandleFunc("GET /api/v1/payroll", employeeHandler.RunPayroll)
}

func (s *Server) Start() {
	httpServer := &http.Server{
		Addr:    ":" + s.config.Port,
		Handler: s.router,
	}

	go func() {
		s.logger.Info("server starting", "port", s.config.Port)
		if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			s.logger.Error("server failed to start", "error", err)
			os.Exit(1)
		}
	}()

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

	s.logger.Info("shutting down server gracefully")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := httpServer.Shutdown(ctx); err != nil {
		s.logger.Error("server shutdown failed", "error", err)
	} else {
		s.logger.Info("server stopped")
	}
}
