package handlers import ( "errors" "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/treytartt/casera-api/internal/dto/requests" "github.com/treytartt/casera-api/internal/middleware" "github.com/treytartt/casera-api/internal/models" "github.com/treytartt/casera-api/internal/services" ) // ContractorHandler handles contractor-related HTTP requests type ContractorHandler struct { contractorService *services.ContractorService } // NewContractorHandler creates a new contractor handler func NewContractorHandler(contractorService *services.ContractorService) *ContractorHandler { return &ContractorHandler{contractorService: contractorService} } // ListContractors handles GET /api/contractors/ func (h *ContractorHandler) ListContractors(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) response, err := h.contractorService.ListContractors(user.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, response) } // GetContractor handles GET /api/contractors/:id/ func (h *ContractorHandler) GetContractor(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) contractorID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid contractor ID"}) return } response, err := h.contractorService.GetContractor(uint(contractorID), user.ID) if err != nil { switch { case errors.Is(err, services.ErrContractorNotFound): c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) case errors.Is(err, services.ErrContractorAccessDenied): c.JSON(http.StatusForbidden, gin.H{"error": err.Error()}) default: c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } return } c.JSON(http.StatusOK, response) } // CreateContractor handles POST /api/contractors/ func (h *ContractorHandler) CreateContractor(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) var req requests.CreateContractorRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } response, err := h.contractorService.CreateContractor(&req, user.ID) if err != nil { if errors.Is(err, services.ErrResidenceAccessDenied) { c.JSON(http.StatusForbidden, gin.H{"error": err.Error()}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusCreated, response) } // UpdateContractor handles PUT/PATCH /api/contractors/:id/ func (h *ContractorHandler) UpdateContractor(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) contractorID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid contractor ID"}) return } var req requests.UpdateContractorRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } response, err := h.contractorService.UpdateContractor(uint(contractorID), user.ID, &req) if err != nil { switch { case errors.Is(err, services.ErrContractorNotFound): c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) case errors.Is(err, services.ErrContractorAccessDenied): c.JSON(http.StatusForbidden, gin.H{"error": err.Error()}) default: c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } return } c.JSON(http.StatusOK, response) } // DeleteContractor handles DELETE /api/contractors/:id/ func (h *ContractorHandler) DeleteContractor(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) contractorID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid contractor ID"}) return } err = h.contractorService.DeleteContractor(uint(contractorID), user.ID) if err != nil { switch { case errors.Is(err, services.ErrContractorNotFound): c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) case errors.Is(err, services.ErrContractorAccessDenied): c.JSON(http.StatusForbidden, gin.H{"error": err.Error()}) default: c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } return } c.JSON(http.StatusOK, gin.H{"message": "Contractor deleted successfully"}) } // ToggleFavorite handles POST /api/contractors/:id/toggle-favorite/ func (h *ContractorHandler) ToggleFavorite(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) contractorID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid contractor ID"}) return } response, err := h.contractorService.ToggleFavorite(uint(contractorID), user.ID) if err != nil { switch { case errors.Is(err, services.ErrContractorNotFound): c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) case errors.Is(err, services.ErrContractorAccessDenied): c.JSON(http.StatusForbidden, gin.H{"error": err.Error()}) default: c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } return } c.JSON(http.StatusOK, response) } // GetContractorTasks handles GET /api/contractors/:id/tasks/ func (h *ContractorHandler) GetContractorTasks(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) contractorID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid contractor ID"}) return } response, err := h.contractorService.GetContractorTasks(uint(contractorID), user.ID) if err != nil { switch { case errors.Is(err, services.ErrContractorNotFound): c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) case errors.Is(err, services.ErrContractorAccessDenied): c.JSON(http.StatusForbidden, gin.H{"error": err.Error()}) default: c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } return } c.JSON(http.StatusOK, response) } // ListContractorsByResidence handles GET /api/contractors/by-residence/:residence_id/ func (h *ContractorHandler) ListContractorsByResidence(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) residenceID, err := strconv.ParseUint(c.Param("residence_id"), 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid residence ID"}) return } response, err := h.contractorService.ListContractorsByResidence(uint(residenceID), user.ID) if err != nil { if errors.Is(err, services.ErrResidenceAccessDenied) { c.JSON(http.StatusForbidden, gin.H{"error": err.Error()}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, response) } // GetSpecialties handles GET /api/contractors/specialties/ func (h *ContractorHandler) GetSpecialties(c *gin.Context) { specialties, err := h.contractorService.GetSpecialties() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, specialties) }