package server

import (
	"context"
	"fmt"
	"github.com/gofiber/fiber/v2"
	"github.com/themakers/hlog"
	"go.uber.org/zap"
	"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils"
)

type ServerConfig struct {
	Logger      *zap.Logger
	Hlog        hlog.Logger
	Controllers []Controller
	JWTConfig   *models.JWTConfiguration
}

type Server struct {
	Logger      *zap.Logger
	Hlog        hlog.Logger
	Controllers []Controller
	app         *fiber.App
}

func NewServer(config ServerConfig) *Server {
	app := fiber.New()

	jwtUtil := utils.NewJWT(config.JWTConfig)
	app.Use(utils.NewAuthenticator(jwtUtil))
	app.Use(log_mw.ContextLogger(config.Hlog))

	s := &Server{
		Logger:      config.Logger,
		Controllers: config.Controllers,
		Hlog:        config.Hlog,
		app:         app,
	}

	s.registerRoutes()

	return s
}

func (s *Server) Start(addr string) error {
	if err := s.app.Listen(addr); err != nil {
		s.Logger.Error("Failed to start server", zap.Error(err))
		return err
	}
	return nil
}

func (s *Server) Shutdown(ctx context.Context) error {
	return s.app.Shutdown()
}

func (s *Server) registerRoutes() {
	for _, c := range s.Controllers {
		router := s.app.Group(c.Name())
		c.Register(router)
	}
}

type Controller interface {
	Register(router fiber.Router)
	Name() string
}

func (s *Server) ListRoutes() {
	fmt.Println("Registered routes:")
	for _, stack := range s.app.Stack() {
		for _, route := range stack {
			fmt.Printf("%s %s\n", route.Method, route.Path)
		}
	}
}
