package handler import ( "bugulma/backend/internal/service" "net/http" "strconv" "time" "github.com/gin-gonic/gin" ) // PublicTransportHandler handles endpoints for public transport data type PublicTransportHandler struct { service *service.PublicTransportService schedule *service.ScheduleService } // NewPublicTransportHandler creates a new handler func NewPublicTransportHandler(svc *service.PublicTransportService, schedule *service.ScheduleService) *PublicTransportHandler { return &PublicTransportHandler{service: svc, schedule: schedule} } // GetMetadata returns general metadata about the public transport dataset func (h *PublicTransportHandler) GetMetadata(c *gin.Context) { c.JSON(http.StatusOK, h.service.GetMetadata()) } // ListStops returns a list of common stops func (h *PublicTransportHandler) ListStops(c *gin.Context) { stops := h.service.ListStops() c.JSON(http.StatusOK, gin.H{"stops": stops}) } // GetStop returns a single stop by key func (h *PublicTransportHandler) GetStop(c *gin.Context) { id := c.Param("id") if st, ok := h.service.GetStop(id); ok { c.JSON(http.StatusOK, st) return } c.JSON(http.StatusNotFound, gin.H{"error": "stop not found"}) } // SearchStops searches stops by name func (h *PublicTransportHandler) SearchStops(c *gin.Context) { q := c.Query("q") res := h.service.SearchStops(q) c.JSON(http.StatusOK, gin.H{"results": res}) } // GetGTFSFile returns a raw GTFS file from the export directory func (h *PublicTransportHandler) GetGTFSFile(c *gin.Context) { filename := c.Param("filename") content, err := h.service.ReadGTFSFile(filename) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "file not found"}) return } c.Data(http.StatusOK, "text/plain; charset=utf-8", []byte(content)) } // GetNextDepartures returns upcoming departures for a stop func (h *PublicTransportHandler) GetNextDepartures(c *gin.Context) { if h.schedule == nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "schedule service not available"}) return } stopID := c.Param("id") fromStr := c.DefaultQuery("from", "") limitStr := c.DefaultQuery("limit", "10") var from time.Time var err error if fromStr == "" { from = time.Now().UTC() } else { from, err = time.Parse(time.RFC3339, fromStr) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid from time, expected RFC3339"}) return } } limit, err := strconv.Atoi(limitStr) if err != nil || limit <= 0 { limit = 10 } deps, err := h.schedule.GetNextDepartures(c.Request.Context(), stopID, from, limit) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"departures": deps}) }