package controller import ( "net/http" "strconv" "users_management/m/config" "users_management/m/middleware" "users_management/m/model/dto/req" "users_management/m/usecase" "users_management/m/utils/common" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type NearestDeviceController struct { nearestDeviceUC usecase.NearestDeviceUseCase rg *gin.RouterGroup cfg *config.Config } func NewNearestDeviceController(nearestDeviceUC usecase.NearestDeviceUseCase, rg *gin.RouterGroup, cfg *config.Config) *NearestDeviceController { return &NearestDeviceController{ nearestDeviceUC: nearestDeviceUC, rg: rg, cfg: cfg, } } func (c *NearestDeviceController) Route() { nearestDevices := c.rg.Group("/nearest-devices") nearestDevices.Use(middleware.ConditionalRequireAnyRole(c.cfg, "Teknisi", "Admin", "Super Admin")) { nearestDevices.POST("/search", c.getNearestDevices) nearestDevices.GET("/:id", c.getNearestDeviceByID) nearestDevices.POST("/towers/search", c.getNearestTowers) nearestDevices.GET("/towers/:id", c.getNearestTowerByID) // GET /odp/search removed — use POST /search with device_type="ODP" } } func (c *NearestDeviceController) getNearestTowers(ctx *gin.Context) { var request req.NearestTowerDTO if err := ctx.ShouldBindJSON(&request); err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, err.Error()) return } towers, err := c.nearestDeviceUC.GetNearestTowers(request) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, err.Error()) return } response := gin.H{ "towers": towers, "total": len(towers), "search_params": gin.H{ "latitude": request.Latitude, "longitude": request.Longitude, "radius": request.Radius, "province": request.Province, "city": request.City, "district": request.District, }, } common.SingleResponses(ctx, "Nearest towers retrieved successfully", response) } func (c *NearestDeviceController) getNearestTowerByID(ctx *gin.Context) { id := ctx.Param("id") towerID, err := uuid.Parse(id) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid tower ID") return } // Get user coordinates from query params latStr := ctx.Query("lat") lngStr := ctx.Query("lng") if latStr == "" || lngStr == "" { common.ErrorResponses(ctx, http.StatusBadRequest, "User coordinates (lat, lng) are required") return } userLat, err := strconv.ParseFloat(latStr, 64) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid latitude") return } userLng, err := strconv.ParseFloat(lngStr, 64) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid longitude") return } tower, err := c.nearestDeviceUC.GetNearestTowerByID(towerID, userLat, userLng) if err != nil { common.ErrorResponses(ctx, http.StatusNotFound, err.Error()) return } common.SingleResponses(ctx, "Tower details retrieved successfully", tower) } func (c *NearestDeviceController) getNearestDevices(ctx *gin.Context) { var request req.NearestDeviceDTO if err := ctx.ShouldBindJSON(&request); err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, err.Error()) return } devices, err := c.nearestDeviceUC.GetNearestDevices(request) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, err.Error()) return } response := gin.H{ "devices": devices, "total": len(devices), "search_params": gin.H{ "latitude": request.Latitude, "longitude": request.Longitude, "radius": request.Radius, "province": request.Province, "city": request.City, "district": request.District, }, } common.SingleResponses(ctx, "Nearest devices retrieved successfully", response) } func (c *NearestDeviceController) getNearestDeviceByID(ctx *gin.Context) { id := ctx.Param("id") deviceID, err := uuid.Parse(id) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid device ID") return } // Get user coordinates from query params latStr := ctx.Query("lat") lngStr := ctx.Query("lng") if latStr == "" || lngStr == "" { common.ErrorResponses(ctx, http.StatusBadRequest, "User coordinates (lat, lng) are required") return } userLat, err := strconv.ParseFloat(latStr, 64) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid latitude") return } userLng, err := strconv.ParseFloat(lngStr, 64) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid longitude") return } device, err := c.nearestDeviceUC.GetNearestDeviceByID(deviceID, userLat, userLng) if err != nil { common.ErrorResponses(ctx, http.StatusNotFound, err.Error()) return } common.SingleResponses(ctx, "Device details retrieved successfully", device) } func (c *NearestDeviceController) getNearestODPDevices(ctx *gin.Context) { latStr := ctx.Query("latitude") lngStr := ctx.Query("longitude") radiusStr := ctx.Query("radius") if latStr == "" || lngStr == "" { common.ErrorResponses(ctx, http.StatusBadRequest, "latitude and longitude are required") return } latitude, err := strconv.ParseFloat(latStr, 64) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, "invalid latitude") return } longitude, err := strconv.ParseFloat(lngStr, 64) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, "invalid longitude") return } radius := 0.3 if radiusStr != "" { radius, err = strconv.ParseFloat(radiusStr, 64) if err != nil || radius <= 0 { common.ErrorResponses(ctx, http.StatusBadRequest, "invalid radius") return } } odpType := "ODP" request := req.NearestDeviceDTO{ Latitude: latitude, Longitude: longitude, Radius: radius, DeviceType: &odpType, Limit: 10, } devices, err := c.nearestDeviceUC.GetNearestDevices(request) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, err.Error()) return } response := gin.H{ "devices": devices, "total": len(devices), "search_params": gin.H{ "latitude": latitude, "longitude": longitude, "radius": radius, "device_type": "ODP", "unit": "kilometers", }, } common.SingleResponses(ctx, "Nearest ODP devices retrieved successfully", response) }