package server

import (
	"fmt"
	"log/slog"
	"net/http"
	"os"

	"codeberg.org/nextgo/dbots/internal/config"
	"codeberg.org/nextgo/dbots/internal/db"
	"codeberg.org/nextgo/dbots/internal/discord"
	customMiddlewares "codeberg.org/nextgo/dbots/internal/middleware"
	"codeberg.org/nextgo/dbots/services/admin"
	"codeberg.org/nextgo/dbots/services/auth"
	"codeberg.org/nextgo/dbots/services/bot"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
	"github.com/go-chi/httplog/v3"
)

type Server struct {
	router  *chi.Mux
	queries *db.Queries
	config  config.Config
}

func NewServer(queries *db.Queries, config config.Config) *Server {
	router := chi.NewMux()

	router.Use(httplog.RequestLogger(slog.Default(), &httplog.Options{}))
	router.Use(middleware.Recoverer)
	router.Use(middleware.RequestID)
	router.Use(middleware.RealIP)
	router.Use(customMiddlewares.AuthMiddleware(queries, config.Auth.PasetoKey)) // todo: use this middleware only when necessary
	// i am using this globally cus it uses mocked data lol

	return &Server{
		router:  router,
		queries: queries,
		config:  config,
	}
}

func (s *Server) Register() {
	discordClient := discord.NewClient(
		s.config.Discord.ClientID,
		s.config.Discord.ClientSecret,
		s.config.Discord.RedirectURI,
	)

	authRouter := auth.NewRouter(s.queries, discordClient, s.config.Auth.PasetoKey)
	botRouter := bot.NewRouter(s.queries, discordClient)
	adminRouter := admin.NewRouter(s.queries)

	s.router.Mount("/auth", authRouter.Routes())
	s.router.Mount("/bots", botRouter.Routes())
	s.router.Mount("/admin", adminRouter.Routes())
}

func (s *Server) Start(addr string, port int) {
	s.Register()
	slog.Info("server started", "addr", addr, "port", port)
	if err := http.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), s.router); err != nil {
		slog.Error("error starting server", "port", port, "err", err)
		os.Exit(1)
	}
}
