package server import ( "encoding/json" "net/http" "github.com/food-ai/backend/internal/domain/auth" "github.com/food-ai/backend/internal/domain/diary" "github.com/food-ai/backend/internal/domain/dish" "github.com/food-ai/backend/internal/domain/home" "github.com/food-ai/backend/internal/domain/language" "github.com/food-ai/backend/internal/domain/menu" "github.com/food-ai/backend/internal/infra/middleware" "github.com/food-ai/backend/internal/domain/product" "github.com/food-ai/backend/internal/domain/recipe" "github.com/food-ai/backend/internal/domain/recognition" "github.com/food-ai/backend/internal/domain/recommendation" "github.com/food-ai/backend/internal/domain/savedrecipe" "github.com/food-ai/backend/internal/domain/user" "github.com/food-ai/backend/internal/domain/userproduct" "github.com/go-chi/chi/v5" "github.com/jackc/pgx/v5/pgxpool" ) func NewRouter( pool *pgxpool.Pool, authHandler *auth.Handler, userHandler *user.Handler, recommendationHandler *recommendation.Handler, savedRecipeHandler *savedrecipe.Handler, productHandler *product.Handler, userProductHandler *userproduct.Handler, recognitionHandler *recognition.Handler, menuHandler *menu.Handler, diaryHandler *diary.Handler, homeHandler *home.Handler, dishHandler *dish.Handler, recipeHandler *recipe.Handler, authMiddleware func(http.Handler) http.Handler, allowedOrigins []string, unitsListHandler http.HandlerFunc, cuisineListHandler http.HandlerFunc, tagListHandler http.HandlerFunc, ) *chi.Mux { r := chi.NewRouter() // Global middleware r.Use(middleware.RequestID) r.Use(middleware.Logging) r.Use(middleware.Recovery) r.Use(middleware.CORS(allowedOrigins)) r.Use(middleware.Language) // Public r.Get("/health", healthCheck(pool)) r.Get("/languages", language.List) r.Get("/units", unitsListHandler) r.Get("/cuisines", cuisineListHandler) r.Get("/tags", tagListHandler) r.Route("/auth", func(r chi.Router) { r.Post("/login", authHandler.Login) r.Post("/refresh", authHandler.Refresh) r.Post("/logout", authHandler.Logout) }) // Protected r.Group(func(r chi.Router) { r.Use(authMiddleware) r.Get("/products/search", productHandler.Search) r.Get("/products/barcode/{barcode}", productHandler.GetByBarcode) r.Get("/profile", userHandler.Get) r.Put("/profile", userHandler.Update) r.Get("/recommendations", recommendationHandler.GetRecommendations) r.Route("/saved-recipes", func(r chi.Router) { r.Post("/", savedRecipeHandler.Save) r.Get("/", savedRecipeHandler.List) r.Get("/{id}", savedRecipeHandler.GetByID) r.Delete("/{id}", savedRecipeHandler.Delete) }) r.Route("/user-products", func(r chi.Router) { r.Get("/", userProductHandler.List) r.Post("/", userProductHandler.Create) r.Post("/batch", userProductHandler.BatchCreate) r.Put("/{id}", userProductHandler.Update) r.Delete("/", userProductHandler.DeleteAll) r.Delete("/{id}", userProductHandler.Delete) }) r.Route("/dishes", func(r chi.Router) { r.Get("/", dishHandler.List) r.Get("/search", dishHandler.Search) r.Get("/{id}", dishHandler.GetByID) }) r.Get("/recipes/{id}", recipeHandler.GetByID) r.Route("/menu", func(r chi.Router) { r.Get("/", menuHandler.GetMenu) r.Put("/items/{id}", menuHandler.UpdateMenuItem) r.Delete("/items/{id}", menuHandler.DeleteMenuItem) }) r.Route("/shopping-list", func(r chi.Router) { r.Get("/", menuHandler.GetShoppingList) r.Post("/generate", menuHandler.GenerateShoppingList) r.Patch("/items/{index}/check", menuHandler.ToggleShoppingItem) }) r.Route("/diary", func(r chi.Router) { r.Get("/", diaryHandler.GetByDate) r.Get("/recent", diaryHandler.GetRecent) r.Post("/", diaryHandler.Create) r.Delete("/{id}", diaryHandler.Delete) }) r.Get("/home/summary", homeHandler.GetSummary) r.Route("/ai", func(r chi.Router) { r.Post("/recognize-receipt", recognitionHandler.RecognizeReceipt) r.Post("/recognize-products", recognitionHandler.RecognizeProducts) r.Post("/recognize-dish", recognitionHandler.RecognizeDish) r.Get("/jobs", recognitionHandler.ListTodayJobs) r.Get("/jobs/history", recognitionHandler.ListAllJobs) r.Get("/jobs/{id}", recognitionHandler.GetJob) r.Get("/jobs/{id}/stream", recognitionHandler.GetJobStream) r.Get("/product-jobs", recognitionHandler.ListRecentProductJobs) r.Get("/product-jobs/history", recognitionHandler.ListAllProductJobs) r.Get("/product-jobs/{id}", recognitionHandler.GetProductJob) r.Get("/product-jobs/{id}/stream", recognitionHandler.GetProductJobStream) r.Post("/generate-menu", menuHandler.GenerateMenu) }) }) return r } func healthCheck(pool *pgxpool.Pool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { dbStatus := "connected" if err := pool.Ping(r.Context()); err != nil { dbStatus = "disconnected" } w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]string{ "status": "ok", "version": "0.1.0", "db": dbStatus, }) } }