package services import ( "errors" "lost-and-found/internal/models" "lost-and-found/internal/repositories" "time" "gorm.io/gorm" ) type LostItemService struct { lostItemRepo *repositories.LostItemRepository categoryRepo *repositories.CategoryRepository auditLogRepo *repositories.AuditLogRepository } func NewLostItemService(db *gorm.DB) *LostItemService { return &LostItemService{ lostItemRepo: repositories.NewLostItemRepository(db), categoryRepo: repositories.NewCategoryRepository(db), auditLogRepo: repositories.NewAuditLogRepository(db), } } // CreateLostItemRequest represents create lost item data type CreateLostItemRequest struct { Name string `json:"name" binding:"required"` CategoryID uint `json:"category_id" binding:"required"` Color string `json:"color"` Location string `json:"location"` Description string `json:"description" binding:"required"` DateLost time.Time `json:"date_lost" binding:"required"` } // UpdateLostItemRequest represents update lost item data type UpdateLostItemRequest struct { Name string `json:"name"` CategoryID uint `json:"category_id"` Color string `json:"color"` Location string `json:"location"` Description string `json:"description"` DateLost time.Time `json:"date_lost"` } // GetAllLostItems gets all lost items func (s *LostItemService) GetAllLostItems(page, limit int, status, category, search string, userID *uint) ([]models.LostItemResponse, int64, error) { lostItems, total, err := s.lostItemRepo.FindAll(page, limit, status, category, search, userID) if err != nil { return nil, 0, err } var responses []models.LostItemResponse for _, lostItem := range lostItems { responses = append(responses, lostItem.ToResponse()) } return responses, total, nil } // GetLostItemByID gets lost item by ID func (s *LostItemService) GetLostItemByID(id uint) (*models.LostItem, error) { return s.lostItemRepo.FindByID(id) } // CreateLostItem creates a new lost item report func (s *LostItemService) CreateLostItem(userID uint, req CreateLostItemRequest, ipAddress, userAgent string) (*models.LostItem, error) { // Verify category exists if _, err := s.categoryRepo.FindByID(req.CategoryID); err != nil { return nil, errors.New("invalid category") } lostItem := &models.LostItem{ UserID: userID, Name: req.Name, CategoryID: req.CategoryID, Color: req.Color, Location: req.Location, Description: req.Description, DateLost: req.DateLost, Status: models.LostItemStatusActive, } if err := s.lostItemRepo.Create(lostItem); err != nil { return nil, errors.New("failed to create lost item report") } // Log audit s.auditLogRepo.Log(&userID, models.ActionCreate, models.EntityLostItem, &lostItem.ID, "Lost item report created: "+lostItem.Name, ipAddress, userAgent) // Load with relations return s.lostItemRepo.FindByID(lostItem.ID) } // UpdateLostItem updates a lost item report func (s *LostItemService) UpdateLostItem(userID, lostItemID uint, req UpdateLostItemRequest, ipAddress, userAgent string) (*models.LostItem, error) { lostItem, err := s.lostItemRepo.FindByID(lostItemID) if err != nil { return nil, err } // Only owner can update if lostItem.UserID != userID { return nil, errors.New("unauthorized to update this lost item report") } // Only active reports can be updated if !lostItem.IsActive() { return nil, errors.New("cannot update non-active lost item report") } // Update fields if req.Name != "" { lostItem.Name = req.Name } if req.CategoryID != 0 { // Verify category exists if _, err := s.categoryRepo.FindByID(req.CategoryID); err != nil { return nil, errors.New("invalid category") } lostItem.CategoryID = req.CategoryID } if req.Color != "" { lostItem.Color = req.Color } if req.Location != "" { lostItem.Location = req.Location } if req.Description != "" { lostItem.Description = req.Description } if !req.DateLost.IsZero() { lostItem.DateLost = req.DateLost } if err := s.lostItemRepo.Update(lostItem); err != nil { return nil, errors.New("failed to update lost item report") } // Log audit s.auditLogRepo.Log(&userID, models.ActionUpdate, models.EntityLostItem, &lostItemID, "Lost item report updated: "+lostItem.Name, ipAddress, userAgent) return lostItem, nil } // UpdateLostItemStatus updates lost item status func (s *LostItemService) UpdateLostItemStatus(userID, lostItemID uint, status string, ipAddress, userAgent string) error { lostItem, err := s.lostItemRepo.FindByID(lostItemID) if err != nil { return err } // Only owner can update if lostItem.UserID != userID { return errors.New("unauthorized to update this lost item report") } if err := s.lostItemRepo.UpdateStatus(lostItemID, status); err != nil { return errors.New("failed to update lost item status") } // Log audit s.auditLogRepo.Log(&userID, models.ActionUpdate, models.EntityLostItem, &lostItemID, "Lost item status updated to: "+status, ipAddress, userAgent) return nil } // DeleteLostItem deletes a lost item report func (s *LostItemService) DeleteLostItem(userID, lostItemID uint, ipAddress, userAgent string) error { lostItem, err := s.lostItemRepo.FindByID(lostItemID) if err != nil { return err } // Only owner can delete if lostItem.UserID != userID { return errors.New("unauthorized to delete this lost item report") } if err := s.lostItemRepo.Delete(lostItemID); err != nil { return errors.New("failed to delete lost item report") } // Log audit s.auditLogRepo.Log(&userID, models.ActionDelete, models.EntityLostItem, &lostItemID, "Lost item report deleted: "+lostItem.Name, ipAddress, userAgent) return nil } // GetLostItemsByUser gets lost items by user func (s *LostItemService) GetLostItemsByUser(userID uint, page, limit int) ([]models.LostItemResponse, int64, error) { lostItems, total, err := s.lostItemRepo.FindByUser(userID, page, limit) if err != nil { return nil, 0, err } var responses []models.LostItemResponse for _, lostItem := range lostItems { responses = append(responses, lostItem.ToResponse()) } return responses, total, nil }