diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/ShoppingListController.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/ShoppingListController.java
index 103d16a027787af01f48ee2589928cf27e717b53..352447b28b4114bf14b0b099861f19b9a1580c34 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/ShoppingListController.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/ShoppingListController.java
@@ -134,8 +134,10 @@ public class ShoppingListController {
         if(product.isEmpty())
             return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
 
+        System.out.println("Removing product from shopping list : " + shoppingListId + " - " + ean);
+
         Optional<ShoppingList> returnVal = shoppingListService
-                .removeProductFromShoppingList(Long.parseLong(shoppingListId), Long.parseLong(ean));
+                .removeProductFromShoppingList(Long.parseLong(ean), Long.parseLong(shoppingListId));
 
         return returnVal.map(list -> ResponseEntity.status(HttpStatus.OK).body(list))
                 .orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND).build());
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/FridgeController.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/FridgeController.java
index 115760fa842ff53a8733956e82227e227646291e..bf2861a67a389e5c622f9e6299ea08b60f883650 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/FridgeController.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/FridgeController.java
@@ -114,24 +114,5 @@ public class FridgeController {
         return fridgeService.wasteProductFromFridge(fridgeProductId).map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
     }
 
-    /**
-     * Deletes all products in a fridge
-     * @param fridgeId the id of the fridge
-     * @return success if the products were deleted, bad request if the fridge doesn't exist
-     *
-    @DeleteMapping("/delete/all/{fridgeId}")
-    public ResponseEntity<String> deleteAllProductsInFridge(@PathVariable("fridgeId") long fridgeId) {
-        try {
-            boolean success = fridgeService.deleteAllProductsInFridge(fridgeId);
-            if (success){
-                return ResponseEntity.ok("Success");
-            }
-            return ResponseEntity.badRequest().body("Fridge not found");
-        } catch (Exception e) {
-            return ResponseEntity.status(500).body("Internal server error");
-        }
-    }
-
-    */
 
 }
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/GroupController.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/GroupController.java
index a33ab537ddf929fb423fc6ab82aed0e7af3babf0..650976945c6354325005bce0f5194e17466ea404 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/GroupController.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/GroupController.java
@@ -19,6 +19,7 @@ import org.springframework.security.core.Authentication;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * Controller for groups API, providing endpoints for group management
@@ -324,4 +325,59 @@ public class GroupController {
         }
     }
 
+    /**
+     * Handles the HTTP DELETE request to remove a user from a group.
+     * @param auth the authentication object containing the username of the user
+     * @return a ResponseEntity object containing the list of groups the user is associated with and an HTTP status code of 200,
+     */
+    @GetMapping("/")
+    public ResponseEntity<List<UserGroupAsso>> getAllGroupsByUser(Authentication auth) {
+        return ResponseEntity.ok(groupService.getUserGroupAssoByUserName(auth.getName()));
+    }
+
+
+    /**
+     * Handles the HTTP DELETE request to remove a user from a group.
+     * @param groupId the ID of the group to get the members of
+     * @param username the username of the user to remove from the group
+     * @param auth the authentication object containing the username of the user
+     * @return a ResponseEntity object containing the list of groups the
+     * user is associated with and an HTTP status code of 200,
+     */
+    @DeleteMapping("/removeUser/{groupId}/{username}")
+    public ResponseEntity<?> removeUserFromGroup(@PathVariable("groupId") long groupId,
+                                                 @PathVariable("username") String username,
+                                                 Authentication auth) {
+        Optional<User> groupAdminOpt = userService.getUserFromUsername(auth.getName());
+        if (groupAdminOpt.isPresent()) {
+            User groupAdmin = groupAdminOpt.get();
+            if (!(groupService.isUserAssociatedWithGroup(groupAdmin.getUsername(), groupId)
+                    && (groupService.getUserGroupAssoAuthority(groupAdmin.getUsername(), groupId).equals("ADMIN"))
+            || groupAdmin.getUsername().equals(username)))
+                return ResponseEntity.status(HttpStatus.FORBIDDEN).body("You are not authorized to remove this user.");
+        }
+
+        Optional<Group> groupOpt = groupService.getGroupById(groupId);
+        Optional<User> userOpt = userService.getUserFromUsername(username);
+
+        if (groupOpt.isEmpty() || userOpt.isEmpty()) {
+            return ResponseEntity.notFound().build();
+        }
+
+        User user = userOpt.get();
+        UserGroupAsso userGroupAsso = user.getGroup().stream()
+                .filter(asso -> asso.getGroup().getGroupId() == groupId)
+                .findFirst()
+                .orElse(null);
+
+        if (userGroupAsso != null) {
+            groupService.removeUserFromGroup(userGroupAsso);
+            return ResponseEntity.ok("User removed successfully.");
+        } else {
+            return ResponseEntity.notFound().build();
+        }
+    }
+
+
+
 }
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/WasteController.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/WasteController.java
index efb3e0361b544a547bcb51eba8c0bb1632d464e6..ff28172f2623650fcb510fb0e702bcd8df6143bb 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/WasteController.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/group/WasteController.java
@@ -79,4 +79,40 @@ public class WasteController {
         return wasteService.getCakeDiagram(groupId).map(ResponseEntity::ok).orElseGet(()->ResponseEntity.notFound().build());
     }
 
+
+    /**
+     * Get the information of the last months of a specific group.
+     *
+     * @param groupId the id of the group to get the information for
+     * @return a ResponseEntity object containing an array of doubles representing the waste for each category
+     * in the last four months, or a not found response if the group does not exist or has no waste data
+     */
+    @GetMapping("/statistic/lastMonths/{groupId}")
+    public ResponseEntity<double[]> getInformationOfLastMoths(@PathVariable("groupId") long groupId){
+        return wasteService.getLastMonth(groupId).map(ResponseEntity::ok).orElseGet(()->ResponseEntity.notFound().build());
+    }
+
+    /**
+     * Retrieves the amount of money lost due to expired products in a specific group.
+     * The amount is calculated based on the total cost of the expired products.
+     *
+     * @param groupId the ID of the group to retrieve the lost money from
+     * @return a ResponseEntity with the lost money as a Double if found, or a ResponseEntity with status 404 if the group is not found
+     */
+    @GetMapping("/statistic/lostMoney/{groupId}")
+    public ResponseEntity<Double> getLostMoney(@PathVariable("groupId") long groupId){
+        return wasteService.getLostMoney(groupId).map(ResponseEntity::ok).orElseGet(()->ResponseEntity.notFound().build());
+    }
+
+    /**
+     * Retrieves the amount of CO2 emitted annually per person in a specific group.
+     *
+     * @param groupId the ID of the group to retrieve the statistic for
+     * @return a ResponseEntity containing the amount of CO2 emitted annually per person in the group,
+     *         or a ResponseEntity with HTTP status 404 (not found) if the group or data is not found
+     */
+    @GetMapping("/statistic/annuallyCO2/{groupId}")
+    public ResponseEntity<Double> getCO2Annually(@PathVariable("groupId") long groupId){
+        return wasteService.getCO2PerPerson(groupId).map(ResponseEntity::ok).orElseGet(()->ResponseEntity.notFound().build());
+    }
 }
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/product/ProductController.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/product/ProductController.java
index b7755e34186891752ec36cbc873b948d166e97dc..5d81db83a00577a97135789baf8d1f3b8e6880b9 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/product/ProductController.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/product/ProductController.java
@@ -8,6 +8,7 @@ import ntnu.idatt2016.v233.SmartMat.service.AllergyService;
 import ntnu.idatt2016.v233.SmartMat.service.product.CategoryService;
 import ntnu.idatt2016.v233.SmartMat.service.product.ProductService;
 import ntnu.idatt2016.v233.SmartMat.util.CategoryUtil;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
@@ -110,13 +111,13 @@ public class ProductController {
      * @return The product that was deleted.
      */
     @DeleteMapping("ean/{ean}")
-    public ResponseEntity<Product> deleteProduct(@PathVariable long ean) {
+    public ResponseEntity<String> deleteProduct(@PathVariable long ean) {
         Optional<Product> product = productService.getProductById(ean);
         if(product.isPresent()) {
             productService.deleteProductById(product.get().getEan());
-            return ResponseEntity.ok(product.get());
+            return ResponseEntity.ok("Product deleted");
         }
-        return ResponseEntity.notFound().build();
+        return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Product not found");
     }
 
 
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/user/UserController.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/user/UserController.java
index 9bb5d58d78aef857d41d92a7d0d3cf8d12afc0b4..15290417f52ed467a8a7ea0aef70fb2197127938 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/user/UserController.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/controller/user/UserController.java
@@ -6,16 +6,19 @@ import ntnu.idatt2016.v233.SmartMat.dto.request.AllergyRequest;
 import ntnu.idatt2016.v233.SmartMat.dto.request.RegisterUserRequest;
 import ntnu.idatt2016.v233.SmartMat.dto.enums.Authority;
 import ntnu.idatt2016.v233.SmartMat.dto.request.UpdateUserRequest;
+import ntnu.idatt2016.v233.SmartMat.entity.product.Allergy;
 import ntnu.idatt2016.v233.SmartMat.entity.user.User;
 import ntnu.idatt2016.v233.SmartMat.service.user.UserService;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.ArrayList;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 
 /**
@@ -105,14 +108,13 @@ public class UserController {
      * @return a ResponseEntity with a boolean indicating whether the operation was successful
      */
     @PostMapping("/addAllergy")
-    public ResponseEntity<Boolean> addAllergyToUser(@RequestBody AllergyRequest allergyRequest) {
-        try {
-            return userService.addAllergyToUser(allergyRequest.getUsername(), allergyRequest.getAllergyName())
-                    .map(user -> ResponseEntity.ok(user.getAllergies().size() > 0))
-                    .orElseGet(() -> ResponseEntity.notFound().build());
-        }catch (Exception e){
-            return ResponseEntity.status(409).body(false);
-        }
+    public ResponseEntity<String> addAllergyToUser(@RequestBody AllergyRequest allergyRequest,
+                                                    Authentication authentication) {
+        if(!allergyRequest.getUsername().equals(authentication.getName()) &&
+                !authentication.getAuthorities().contains(new SimpleGrantedAuthority(Authority.ADMIN.name())))
+            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
+
+        return userService.addAllergyToUser(allergyRequest.getUsername(), allergyRequest.getAllergyName());
     }
 
     /**
@@ -122,14 +124,14 @@ public class UserController {
      * @return a ResponseEntity with a boolean indicating whether the operation was successful
      */
     @DeleteMapping("/deleteAllergy")
-    public ResponseEntity<Boolean> deleteAllergyFromUser(@RequestBody AllergyRequest allergyRequest) {
-        try {
-            return userService.deleteAllergy(allergyRequest.getUsername(), allergyRequest.getAllergyName())
-                    .map(user -> ResponseEntity.ok(true))
-                    .orElseGet(() -> ResponseEntity.notFound().build());
-        }catch (Exception e){
-            return ResponseEntity.status(409).body(false);
-        }
+    public ResponseEntity<String> deleteAllergyFromUser(@RequestBody AllergyRequest allergyRequest,
+                                                         Authentication authentication) {
+        if(!allergyRequest.getUsername().equals(authentication.getName()) &&
+                !authentication.getAuthorities().contains(new SimpleGrantedAuthority(Authority.ADMIN.name())))
+            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
+
+        return userService.removeAllergyFromUser(allergyRequest.getUsername(), allergyRequest.getAllergyName());
+
     }
 
 
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/dto/request/FridgeProductRequest.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/dto/request/FridgeProductRequest.java
index bbe5b8717bb183192619d446f01a6d6ab502974e..0df58b4fe4b21788385ec234ef449307c5b7239c 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/dto/request/FridgeProductRequest.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/dto/request/FridgeProductRequest.java
@@ -3,7 +3,6 @@ package ntnu.idatt2016.v233.SmartMat.dto.request;
 /**
  * FridgeProductRequest is a record class representing a request to add a product to a fridge.
  * @param groupId the id of the group
- * @param productId the id of the product
  */
-public record FridgeProductRequest(long fridgeProductId, long groupId, long ean, int amount, int days) {
+public record FridgeProductRequest(long fridgeProductId, long groupId, long ean, int amount, int days, double price) {
 }
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/Recipe.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/Recipe.java
index c42c4093fbf6347cbe811bb3535e97acef616538..b4ce8bf285511ec93e0bb6fdd45affb96aad094f 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/Recipe.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/Recipe.java
@@ -40,6 +40,12 @@ public class Recipe {
     @Column(name = "recipe_description")
     String description;
     
+    @Column(name = "image_url")
+    String imageUrl;
+
+    @Column(name = "guide")
+    String guide;
+    
     @ManyToMany(fetch = FetchType.LAZY,
             cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}
             ,mappedBy = "recipes"
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/Waste.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/Waste.java
index b876946b6c7dd762dad3566334e1210241e223e9..567f074c7863a26219a5ac9227019bdc9ad94203 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/Waste.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/Waste.java
@@ -53,4 +53,7 @@ public class Waste {
     @Column(name = "unit")
     String unit;
 
+    @Column(name = "buy_price")
+    double buyPrice;
+
 }
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/fridgeProduct/FridgeProductAsso.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/fridgeProduct/FridgeProductAsso.java
index 8e82358929612d141ff28269560da43a835fa5dd..eb660c4948666ee397d16796bc5ee2e57a528640 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/fridgeProduct/FridgeProductAsso.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/fridgeProduct/FridgeProductAsso.java
@@ -2,6 +2,8 @@ package ntnu.idatt2016.v233.SmartMat.entity.fridgeProduct;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonIncludeProperties;
 import jakarta.persistence.*;
 import lombok.*;
 import ntnu.idatt2016.v233.SmartMat.entity.group.Fridge;
@@ -11,7 +13,7 @@ import java.sql.Date;
 
 @AllArgsConstructor
 @NoArgsConstructor
-@Getter @Setter
+@Data
 @Entity(name = "fridge_product")
 @Builder
 public class FridgeProductAsso {
@@ -23,12 +25,13 @@ public class FridgeProductAsso {
 
     @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
     @JoinColumn(name = "fridge_id")
-    @JsonIgnoreProperties({"products"})
+    @JsonIgnore
     private Fridge fridgeId;
 
     @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
     @JoinColumn(name = "ean")
-    @JsonIgnoreProperties({"fridges"})
+    @JsonIncludeProperties({"HibernateLazyInitializer", "handler", "ean", "name", "description", "category",
+            "url", "allergies", "bestBefore", "expirationDate", "unit", "amount"})
     private Product ean;
 
     @Column(name = "purchase_date")
@@ -40,5 +43,8 @@ public class FridgeProductAsso {
     @Column(name = "amount")
     private double amount;
 
+    @Column(name = "buy_price")
+    private double buyPrice;
+
 
 }
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/Fridge.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/Fridge.java
index 18bbfb732438f7ac86aaaca02fde6cdbec14ae63..537c640223ddc5cfe829c703a37ea2965f20e941 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/Fridge.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/Fridge.java
@@ -42,7 +42,7 @@ public class Fridge{
     @OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH},
             fetch = FetchType.LAZY, mappedBy = "fridgeId")
     @OnDelete(action = OnDeleteAction.CASCADE)
-    @JsonIgnoreProperties("fridge")
+    @JsonIgnoreProperties("fridgeId")
     List<FridgeProductAsso> products;
 
 
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/Group.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/Group.java
index c390052ee47bd59e9df60ff40d80a7db45d52d9e..346ccd7fb82b696d451775fedcb542fa0f34b758 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/Group.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/Group.java
@@ -56,8 +56,10 @@ public class Group {
     private ShoppingList shoppingList;
 
 
-    @OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH},
-            fetch = FetchType.LAZY, mappedBy = "group")
+    @OneToMany(cascade = {CascadeType.ALL},
+            fetch = FetchType.LAZY, mappedBy = "group",
+            orphanRemoval = true
+    )
     @JsonIgnoreProperties("group")
     private List<UserGroupAsso> user = new ArrayList<>();
 
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/UserGroupAsso.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/UserGroupAsso.java
index 5c90e08c389f8ddf218412386a0bf3ccd156f082..cf3b0fca6be1baeaa5cb6570cd0210d947799a1d 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/UserGroupAsso.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/group/UserGroupAsso.java
@@ -1,5 +1,6 @@
 package ntnu.idatt2016.v233.SmartMat.entity.group;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import jakarta.persistence.*;
 import lombok.*;
@@ -26,13 +27,13 @@ public class UserGroupAsso {
     @ManyToOne
     @MapsId("username")
     @JoinColumn(name = "username")
-    @JsonIgnoreProperties("group")
+    @JsonIgnore
     private User user;
 
     @ManyToOne
     @MapsId("group_id")
     @JoinColumn(name = "group_id")
-    @JsonIgnoreProperties({"group", "user"})
+    @JsonIgnoreProperties({"user", "fridge", "shoppingList"})
     private Group group;
 
     @Column(name = "primary_group")
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/product/Allergy.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/product/Allergy.java
index 77870ee42c8df6c2a87d571952e8d8935b5901c6..dc776c200390eef2a571df2e83054c97b47d08e2 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/product/Allergy.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/product/Allergy.java
@@ -9,6 +9,7 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 import ntnu.idatt2016.v233.SmartMat.entity.user.User;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -49,4 +50,15 @@ public class Allergy{
     @JsonIgnore
     private List<User> users;
 
+    /**
+     * adds a user to the allergy
+     * @param tempuser adds a user to the list of users with this allergy
+     */
+    public void addUser(User tempuser) {
+        if (users == null)
+            users = new ArrayList<>();
+
+        users.add(tempuser);
+
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/product/Product.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/product/Product.java
index 3f3840db584c0c651f19a3e2f5d41bdf6b95f3b2..71f295cd4627c3a5f7882d78920f050e395fe266 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/product/Product.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/product/Product.java
@@ -2,6 +2,7 @@ package ntnu.idatt2016.v233.SmartMat.entity.product;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonIncludeProperties;
 import jakarta.persistence.*;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
@@ -52,7 +53,7 @@ public class Product{
     @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH},
             fetch = FetchType.LAZY)
     @JoinColumn(name = "category_name")
-    @JsonIgnore
+    @JsonIncludeProperties("categoryName")
     Category category;
 
     @Column(name = "image_url")
@@ -72,13 +73,12 @@ public class Product{
 
     @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH},
             fetch = FetchType.LAZY, mappedBy = "products")
-    @JsonIgnoreProperties({"products", "users"})
+    @JsonIncludeProperties("name")
     List<Allergy> allergies;
 
     @OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH},
             fetch = FetchType.LAZY, mappedBy = "ean")
     @OnDelete(action = OnDeleteAction.CASCADE)
-    @JsonIgnoreProperties({"products"})
     @JsonIgnore
     List<FridgeProductAsso> fridges;
     
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/user/User.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/user/User.java
index 8f9f5967ffd42d4048bf28eb6c6147821fdbc6bd..e857f458d53a0eec4bc8acbec59faa7aee44e97c 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/user/User.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/entity/user/User.java
@@ -55,13 +55,13 @@ public class User implements UserDetails {
     private Date dateOfBirth;
 
 
-    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
-    @JoinColumn(name = "username")
+    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
     @JsonIgnore
     private List<UserGroupAsso> group;
 
 
-    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH},
+    @ManyToMany(fetch = FetchType.LAZY,
+            cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH},
             mappedBy = "users")
     @JsonIgnoreProperties({"users", "products"})
     private List<Allergy> allergies;
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/RecipeRepository.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/RecipeRepository.java
index 54d98c6c3398fa0ae906bb77e43177a1f3077f76..122fda1f81b8bcef94b3207023c7eb84d4a6edb4 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/RecipeRepository.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/RecipeRepository.java
@@ -78,7 +78,7 @@ public interface RecipeRepository extends JpaRepository<Recipe, Long> {
     List<Object[]> findTop5RecipesWithProductsRaw(@Param("fridgeId") long fridgeId);
         
     @Query( value = """
-        SELECT r.recipe_id, r.recipe_name,r.recipe_description, COUNT(fp.ean) as product_count
+        SELECT r.recipe_id, r.recipe_name,r.recipe_description,r.image_url,r.guide, COUNT(fp.ean) as product_count
         FROM recipe r
         LEFT JOIN recipe_product rp ON r.recipe_id = rp.recipe_id
         LEFT JOIN fridge_product fp ON rp.ean = fp.ean AND fp.fridge_id = :fridgeId
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/group/GroupRepository.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/group/GroupRepository.java
index 6363b44990e2779e83fa589673c684939701231d..e1f3278481f0b498efb7b1b4ba4beb203f3a39ec 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/group/GroupRepository.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/group/GroupRepository.java
@@ -47,4 +47,7 @@ public interface GroupRepository extends JpaRepository<Group, Long> {
 
     Optional<Group> findByLinkCode(String linkCode);
 
+    @Query(value = "SELECT count(*) FROM user_group where group_id = :groupId", nativeQuery = true)
+    int countAllUserInGroup(@Param("groupId") long groupId);
+
 }
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/group/UserGroupAssoRepository.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/group/UserGroupAssoRepository.java
index 77f294fc3cb98207701c5c2bf9eb9c155f2c43eb..07d3739543d9d39527e01eac24b404b0e3621d2e 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/group/UserGroupAssoRepository.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/repository/group/UserGroupAssoRepository.java
@@ -73,4 +73,12 @@ public interface UserGroupAssoRepository extends JpaRepository<UserGroupAsso, Us
      * @return
      */
     String findAuthorityByUser_UsernameAndGroup_GroupId(String username, long groupId);
+
+
+    /**
+     * Finds all groups a user is a member of
+     * @param username the username of the user
+     * @return a list of all groups the user is a member of
+     */
+    List<UserGroupAsso> findAllByUserUsername(String username);
 }
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/ShoppingListService.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/ShoppingListService.java
index 5caae7454907a07ccc0812547184d93e8e6adce0..c7867e9c482e064e58117c78f316d604d4aed7f6 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/ShoppingListService.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/ShoppingListService.java
@@ -78,6 +78,7 @@ public class ShoppingListService {
         shoppingListRepository.findById(shoppingListId).ifPresent(shoppingList -> {
             productRepository.findById(ean).ifPresent(product -> {
                 shoppingList.addProduct(product);
+                product.addShoppingList(shoppingList);
                 shoppingListRepository.save(shoppingList);
             });
         });
@@ -92,13 +93,14 @@ public class ShoppingListService {
      * @return the shopping list that the product was removed from
      */
     public Optional<ShoppingList> removeProductFromShoppingList(long ean, long shoppingListId){
+        System.out.println("shopping list status : " + shoppingListRepository.findById(shoppingListId).isPresent());
+
             shoppingListRepository.findById(shoppingListId).ifPresent(shoppingList -> {
-            productRepository.findById(ean).ifPresent(product -> {
-                shoppingList.getProducts().remove(product);
-                product.getShoppingLists().remove(shoppingList);
-                productRepository.save(product);
-                shoppingListRepository.save(shoppingList);
-            });
+                productRepository.findById(ean).ifPresent(product -> {
+                    shoppingList.getProducts().remove(product);
+                    product.getShoppingLists().remove(shoppingList);
+                    shoppingListRepository.save(shoppingList);
+                });
             });
 
         return shoppingListRepository.findById(shoppingListId);
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/FridgeService.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/FridgeService.java
index 0c0a92dbb3fcdb31c1312e562f184a48ae02ac93..9071dfa5f38b503f8519af0a5b80a20aa4eaddc0 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/FridgeService.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/FridgeService.java
@@ -69,37 +69,46 @@ public class FridgeService {
      * @param fridgeProductRequest the fridge product request
      * @return the product that was added to the fridge
      */
-    public Optional<Product> addProductToFridge(FridgeProductRequest fridgeProductRequest) {
+    public Optional<Object> addProductToFridge(FridgeProductRequest fridgeProductRequest) {
         Optional<Product> product = productService.getProductById(fridgeProductRequest.ean());
         Optional<Fridge> fridge = fridgeRepository.findByGroupGroupId(fridgeProductRequest.groupId());
+        double price = 100.0;
+        if(fridgeProductRequest.price() != 0.0){
+            price = fridgeProductRequest.price();
+        }
 
         if(product.isEmpty() || fridge.isEmpty()) return Optional.empty();
 
         fridge.get().addProduct(FridgeProductAsso.builder()
-                .fridgeId(fridge.get())
-                .ean(product.get())
-                .amount(fridgeProductRequest.amount())
-                .daysToExpiration(fridgeProductRequest.days())
-                .purchaseDate(java.sql.Date.valueOf(LocalDate.now()))
+                        .fridgeId(fridge.get())
+                        .ean(product.get())
+                        .amount(fridgeProductRequest.amount())
+                        .daysToExpiration(fridgeProductRequest.days())
+                        .purchaseDate(java.sql.Date.valueOf(LocalDate.now()))
+                        .buyPrice(price)
                 .build());
 
         fridgeRepository.save(fridge.get());
-        return product;
-    }
+        return Optional.of(product);
 
-    public Optional<FridgeProductAsso> updateProductInFridge(FridgeProductRequest request) {
+    }
+    
+    public Optional<Object> updateProductInFridge(FridgeProductRequest request) {
         Optional<FridgeProductAsso> fridgeProductAsso = fridgeProductAssoRepo.findById(request.fridgeProductId());
         if (fridgeProductAsso.isEmpty()) return Optional.empty();
+        
+        Integer amount = request.amount();
+        Integer days = request.days();
 
-        int amount = request.amount();
-        int days = request.days();
-
-        fridgeProductAsso.get().setAmount(amount);
-        fridgeProductAsso.get().setDaysToExpiration(days);
+        if (amount != null) fridgeProductAsso.get()
+                                .setAmount(request.amount());
 
+        if (days != null) fridgeProductAsso.get()
+                                .setDaysToExpiration(request.days());
+        
         fridgeProductAssoRepo.save(fridgeProductAsso.get());
 
-        return fridgeProductAsso;
+        return Optional.of(fridgeProductAsso);
     }
 
 
@@ -155,12 +164,12 @@ public class FridgeService {
      * @param amount the amount to delete
      * @return an optional containing the fridge product if it exists
      */
-    public Optional<FridgeProductAsso> deleteAmountFromFridge(long fridgeProductId, double amount) {
+    public Optional<Object> deleteAmountFromFridge(long fridgeProductId, double amount) {
         Optional<FridgeProductAsso> fridgeProductAsso = fridgeProductAssoRepo.findAllById(fridgeProductId);
         if(fridgeProductAsso.isEmpty()) return Optional.empty();
         FridgeProductAsso fridgeProductAsso1 = fridgeProductAsso.get();
         if(amount < fridgeProductAsso1.getAmount() ){
-            fridgeProductAsso1.setAmount(fridgeProductAsso1.getAmount() - amount);
+            fridgeProductAsso1.setAmount(fridgeProductAsso1.getAmount() -amount);
             return Optional.of(fridgeProductAssoRepo.save(fridgeProductAsso1));
         } else {
             Group group = fridgeProductAsso1.getFridgeId().getGroup();
@@ -168,7 +177,7 @@ public class FridgeService {
             group.setLevel(GroupUtil.getLevel(group.getPoints()));
             groupRepository.save(group);
             fridgeProductAssoRepo.delete(fridgeProductAsso.get());
-            return Optional.empty();
+            return Optional.of(true);
         }
     }
 
@@ -177,7 +186,7 @@ public class FridgeService {
      * @param fridgeProductId the ID of the fridge product association to delete
      * @return an Optional containing the saved waste object, or an empty Optional if the fridge product association with the given ID is not found
      */
-    public Optional<Waste> wasteProductFromFridge(long fridgeProductId){
+    public Optional<Object> wasteProductFromFridge(long fridgeProductId){
         Optional<FridgeProductAsso> fridgeProductAsso = fridgeProductAssoRepo.findById(fridgeProductId);
         if(fridgeProductAsso.isEmpty()) return Optional.empty();
         FridgeProductAsso fridgeProductAsso1 = fridgeProductAsso.get();
@@ -188,13 +197,7 @@ public class FridgeService {
             group.setLevel(GroupUtil.getLevel(group.getPoints()));
         }
         groupRepository.save(group);
-        return Optional.of(wasteRepository.save(Waste.builder()
-                .amount(fridgeProductAsso1.getAmount())
-                .unit(fridgeProductAsso1.getEan().getUnit())
-                .ean(fridgeProductAsso1.getEan())
-                .groupId(fridgeProductAsso1.getFridgeId().getGroup())
-                .timestamp(new Timestamp(System.currentTimeMillis()))
-                .build()));
+        return Optional.of(wasteRepository.save(Waste.builder().buyPrice(fridgeProductAsso1.getBuyPrice()).amount(fridgeProductAsso1.getAmount()).unit(fridgeProductAsso1.getEan().getUnit()).ean(fridgeProductAsso1.getEan()).groupId(fridgeProductAsso1.getFridgeId().getGroup()).timestamp(new Timestamp(System.currentTimeMillis())).build()));
     }
 
 
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/GroupService.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/GroupService.java
index 484f3ff93f71a911ef9b0bf1424443c5e7389ccc..53daf543777b798f1332672a3ee3ec5831e5fd23 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/GroupService.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/GroupService.java
@@ -1,5 +1,6 @@
 package ntnu.idatt2016.v233.SmartMat.service.group;
 
+import jakarta.transaction.Transactional;
 import lombok.AllArgsConstructor;
 import ntnu.idatt2016.v233.SmartMat.entity.ShoppingList;
 import ntnu.idatt2016.v233.SmartMat.entity.group.Fridge;
@@ -219,4 +220,37 @@ public class GroupService {
         Optional<UserGroupAsso> userGroupAsso = getUserGroupAsso(username, groupId);
         return userGroupAsso.map(UserGroupAsso::getGroupAuthority).orElseThrow(() -> new IllegalArgumentException("User is not associated with group"));
     }
+
+
+    /**
+     * Gets all user group associations for a user
+     * @param username the username of the user
+     * @return a list of all user group associations for the user
+     */
+    public List<UserGroupAsso> getUserGroupAssoByUserName(String username) {
+        return userGroupAssoRepository.findAllByUserUsername(username);
+    }
+
+    /**
+     * removes user_group relatioon
+     * @param username the username of the user
+     * @param groupId the id of the group
+     * @return true if the user is the owner of the group, false otherwise
+     */
+    @Transactional
+    public boolean removeUserFromGroup(UserGroupAsso userGroup) {
+        Group group = groupRepository.findByGroupId(userGroup.getGroup().getGroupId())
+                .orElseThrow(() -> new IllegalArgumentException("Group does not exist"));
+
+        group.getUser().remove(userGroup);
+
+        if (group.getUser().isEmpty()) {
+            groupRepository.delete(group);
+        } else {
+            groupRepository.save(group);
+        }
+
+        userGroupAssoRepository.delete(userGroup);
+        return true;
+    }
 }
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/WasteService.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/WasteService.java
index 8f43267c5e6805f2d2924544274c110db0510b25..dffcfd8e60fe99dc0ee5dbd1747405992dd77318 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/WasteService.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/group/WasteService.java
@@ -1,6 +1,9 @@
 package ntnu.idatt2016.v233.SmartMat.service.group;
 
+import java.nio.channels.FileChannel;
+import java.sql.Date;
 import java.sql.Timestamp;
+import java.util.ArrayList;
 import java.util.List;
 import lombok.AllArgsConstructor;
 import ntnu.idatt2016.v233.SmartMat.dto.request.WasteRequest;
@@ -77,4 +80,41 @@ public class WasteService {
         return group.map(value -> StatisticUtil.getNumberOfWasteByCategoryName(wasteRepository.findByGroupId(value).get()));
     }
 
+    /**
+     * Retrieve an optional array of doubles representing the amount of waste produced in each of the last 4 months for a given group.
+     *
+     * @param groupId a long representing the id of the group whose waste production statistics are to be retrieved
+     * @return an optional array of doubles representing the amount of waste produced in each of the last 4 months for the given group,
+     *         or an empty optional if the group could not be found or no waste was produced in the last 4 months
+     */
+    public Optional<double[]>  getLastMonth(long groupId) {
+        Optional<Group> group = groupRepository.findByGroupId(groupId);
+        return group.map(value -> StatisticUtil.getNumberOfWasteByLastMonth(wasteRepository.findByGroupId(value).get()));
+    }
+
+    /**
+     * Retrieves the lost money in the last month for the group with the given ID.
+     *
+     * @param groupId the ID of the group to retrieve the lost money for
+     * @return an {@code Optional} containing the lost money if the group exists, or empty if it doesn't exist or there are no wastes in the last month
+     */
+    public Optional<Double> getLostMoney(long groupId) {
+        Optional<Group> group = groupRepository.findByGroupId(groupId);
+        return group.map(value -> StatisticUtil.getLostMoneyInLastMonth(wasteRepository.findByGroupId(value).get()));
+    }
+
+    /**
+     * Calculates the annual average CO2 emissions per person in the specified group.
+     *
+     * @param groupId the ID of the group for which to calculate CO2 emissions
+     * @return an Optional containing the annual average CO2 emissions per person, or empty if the group has no users or does not exist
+     */
+    public Optional<Double> getCO2PerPerson(long groupId){
+        Optional<Group> group = groupRepository.findByGroupId(groupId);
+        int number = groupRepository.countAllUserInGroup(groupId);
+        if(number == 0 || group.isEmpty()) return Optional.empty();
+        List<Waste> wastes = wasteRepository.findByGroupId(group.get()).get();
+        return Optional.of(StatisticUtil.getAnnualAverage(wastes,number));
+    }
+
 }
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/user/UserService.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/user/UserService.java
index 5e900fcae7463b980ff957ba5552a7f6f2a3c5e1..3c21d1971e071e2498c5432d7c982662ebd39799 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/service/user/UserService.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/service/user/UserService.java
@@ -8,6 +8,8 @@ import ntnu.idatt2016.v233.SmartMat.entity.user.User;
 import ntnu.idatt2016.v233.SmartMat.repository.AllergyRepository;
 import ntnu.idatt2016.v233.SmartMat.repository.user.UserRepository;
 import ntnu.idatt2016.v233.SmartMat.service.RecipeService;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.stereotype.Service;
 
@@ -132,23 +134,27 @@ public class UserService {
      * Adds allergy to user
      * @param username username of user
      * @param allergyName name of allergy
-     * @return user with added allergy
-     * @throws EntityNotFoundException if user or allergy does not exist
+     * @return string of allergies
      */
-    public Optional<User> addAllergyToUser(String username, String allergyName){
+    public ResponseEntity<String> addAllergyToUser(String username, String allergyName){
 
         Optional<User> user = userRepository.findByUsername(username);
         Optional<Allergy> allergy = allergyRepository.findByName(allergyName);
 
         if (user.isPresent() && allergy.isPresent()){
-            user.get().addAllergy(allergy.get());
-            return Optional.of(userRepository.save(user.get()));
-        } else if (!user.isPresent()) {
-            throw new EntityNotFoundException("User not found");
-        } else if (!allergy.isPresent()) {
-            throw new EntityNotFoundException("Allergy not found");
+            if(user.get().getAllergies().contains(allergy.get())
+                    || allergy.get().getUsers().contains(user.get()))
+                return ResponseEntity.status(HttpStatus.NOT_MODIFIED)
+                        .body("User already has this allergy");
+
+            User tempuser = user.get();
+            allergy.get().addUser(tempuser);
+            tempuser.addAllergy(allergy.get());
+            return ResponseEntity.ok(userRepository.save(tempuser).getAllergies().stream()
+                    .map(Allergy::getName)
+                    .reduce("", (a, b) -> a + " " + b));
         }
-        return Optional.empty();
+        return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Did not find allergy, our user");
     }
 
     /**
@@ -157,40 +163,23 @@ public class UserService {
      * @param allergyName name of allergy
      * @return user with removed allergy
      */
-    public Optional<User> removeAllergyFromUser(String username, String allergyName){
+    public ResponseEntity<String> removeAllergyFromUser(String username, String allergyName){
         Optional<User> user = userRepository.findByUsername(username);
         Optional<Allergy> allergy = allergyRepository.findByName(allergyName);
 
         if (user.isPresent() && allergy.isPresent()){
+            if (!user.get().getAllergies().contains(allergy.get())
+                    || !allergy.get().getUsers().contains(user.get()))
+                return ResponseEntity.status(HttpStatus.NOT_MODIFIED)
+                        .body("User does not have this allergy");
+
             user.get().getAllergies().remove(allergy.get());
-            return Optional.of(userRepository.save(user.get()));
-        } else if (user.isEmpty()) {
-            throw new EntityNotFoundException("User not found");
-        } else if (allergy.isEmpty()) {
-            throw new EntityNotFoundException("Allergy not found");
+            allergy.get().getUsers().remove(user.get());
+            return ResponseEntity.ok(userRepository.save(user.get()).getAllergies().stream()
+                    .map(Allergy::getName)
+                    .reduce("", (a, b) -> a + " " + b));
         }
-        return Optional.empty();
+        return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Did not find allergy, our user");
     }
 
-    /**
-     * Deletes the specified allergy from the user with the given username.
-     *
-     * @param username the username of the user to delete the allergy from
-     * @param allergyName the name of the allergy to delete
-     * @return an Optional containing the updated User object if the operation was successful, or an empty Optional otherwise
-     * @throws EntityNotFoundException if the specified user or allergy cannot be found
-     */
-    public Optional<User> deleteAllergy(String username, String allergyName) {
-        Optional<User> user = userRepository.findByUsername(username);
-        Optional<Allergy> allergy = allergyRepository.findByName(allergyName);
-
-        if (user.isPresent() && allergy.isPresent()) {
-            if(user.get().deleteAllergy(allergy.get())) return Optional.of(userRepository.save(user.get()));
-        } else if (user.isEmpty()) {
-            throw new EntityNotFoundException("User not found");
-        } else {
-            throw new EntityNotFoundException("Allergy not found");
-        }
-        return Optional.empty();
-    }
 }
\ No newline at end of file
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/util/ProductUtil.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/util/ProductUtil.java
index c77016523dfd1161343e576eb1ff5493963f951e..40ba1f50447d72116d2e8def8b1051b41006fcf4 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/util/ProductUtil.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/util/ProductUtil.java
@@ -4,7 +4,9 @@ import ntnu.idatt2016.v233.SmartMat.entity.product.Product;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
@@ -16,52 +18,33 @@ import java.util.regex.Pattern;
 public class ProductUtil {
 
 
-    private static final String[] VOLUME_UNITS = {"ml", "cl", "dl", "l", "g", "kg"};
+    private static final String VOLUME_REGEX = "(\\d+(\\.\\d+)?)\\s*(mls?|centiliters?|deciliters?|liters?|grams?|kilograms?)";
+    private static final Map<String, List<String>> VOLUME_UNIT_VARIATIONS = Map.of(
+            "ml", List.of("ml", "milliliters", "millilitres"),
+            "cl", List.of("cl", "centiliters", "centilitres"),
+            "dl", List.of("dl", "deciliters", "decilitres"),
+            "l", List.of("l", "liters", "litres"),
+            "g", List.of("g", "grams"),
+            "kg", List.of("kg", "kilograms")
+    );
 
-    /**
-     * Gets the volume of a product, if it exists
-     * By looking at the name and description of the product
-     * it will try to first find the volume in the name, and then in the description
-     * It uses pre defined volume units to find the volume
-     * Todo: Make it be able to find volume if the size is definde by count
-     * @param product The product to get the volume from
-     * @return The volume of the product, if it exists
-     */
     public static Optional<List<String>> getVolumeFromProduct(Product product) {
-        for (String desc : Arrays.asList(product.getName(), product.getDescription())) {
-            List<String> words = List.of(desc.split(" "));
-            if (words.size() > 1) {
-                String volume = "";
-                for (String unit : VOLUME_UNITS) {
-                    int i = words.indexOf(unit);
-                    if (i != -1) {
-                        return Optional.of(List.of(words.get(i - 1), unit));
-                    }
-                }
-
-                volume = words.stream().map(word -> Arrays.stream(VOLUME_UNITS).map(unit -> {
-                                    int index = word.indexOf(unit);
-                                    if (index == -1) {
-                                        if (!Pattern.matches("[a-zA-Z]+", word) && ProductUtil.hasNumbers(word)) {
-                                            return word;
-                                        }
-                                        return "";
-                                    }
-                                    return word.substring(0, index) + " " + word.substring(index);
-                                }).findAny().orElse(""))
-                        .filter(ProductUtil::hasNumbers)
-                        .findAny()
-                        .orElse("");
-                if (!volume.equals("")){
-                    return Optional.of(List.of(volume.split(" ")));
+        String desc = product.getName() + " " + product.getDescription();
+        Matcher matcher = Pattern.compile(VOLUME_REGEX).matcher(desc);
+        if (matcher.find()) {
+            String volumeString = matcher.group(1);
+            double volume = Double.parseDouble(volumeString);
+            String unitString = matcher.group(3);
+            for (Map.Entry<String, List<String>> entry : VOLUME_UNIT_VARIATIONS.entrySet()) {
+                if (entry.getValue().contains(unitString)) {
+                    return Optional.of(List.of(String.valueOf(volume), entry.getKey()));
                 }
             }
         }
-
-
         return Optional.empty();
     }
 
+
     /**
      * Checks if a string contains any numbers
      * @param s The string to check
diff --git a/src/main/java/ntnu/idatt2016/v233/SmartMat/util/StatisticUtil.java b/src/main/java/ntnu/idatt2016/v233/SmartMat/util/StatisticUtil.java
index 4ec0de83f551862e720a27aa4185cf3d83a92d6d..9c6f63d7dd01cf2dbbec19d354468afd43fdb4e6 100644
--- a/src/main/java/ntnu/idatt2016/v233/SmartMat/util/StatisticUtil.java
+++ b/src/main/java/ntnu/idatt2016/v233/SmartMat/util/StatisticUtil.java
@@ -3,14 +3,102 @@ package ntnu.idatt2016.v233.SmartMat.util;
 import ntnu.idatt2016.v233.SmartMat.entity.Waste;
 
 import java.sql.Date;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 
 /**
  * A utility class for calculating statistics related to waste and CO2 emissions.
+ * @author Pedro Cardona
+ * @version 1.0
+ * @since 03.05.2023
  */
 public class StatisticUtil {
 
+    private final static double CO2_KG_MEAT = (99.48 + 39.72 + 33.3 + 26.87 + 12.31 + 9.87 )/6.0;
+    private final static double CO2_KG_DAIRY = (23.88 + 4.67 + 3.15)/3;
+    private final static double CO2_KG_BAKED = (4.45 + 1.7 + 1.57)/3;
+    private final static double CO2_KG_VEGETABLE = (2.09 + 0.98 + 0.86 + 0.46)/4;
+    private final static double CO2_KG_OTHER = (CO2_KG_MEAT + CO2_KG_DAIRY  + CO2_KG_BAKED + CO2_KG_VEGETABLE)/4.0;
+
+
+    /**
+     * Calculates the annual average amount of CO2 emissions per person based on a list of waste objects and a number of persons.
+     * @param wastes a list of waste objects
+     * @param number the number of persons
+     * @return the annual average amount of CO2 emissions per person
+     */
+    public static double getAnnualAverage(List<Waste> wastes, int number){
+        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
+        List<Double> CO2 = new ArrayList<>();
+        for(Waste waste: wastes){
+            if(waste.getTimestamp().before(timestamp)) timestamp = waste.getTimestamp();
+            CO2.add(getCO2ByCategory(waste.getEan().getCategory().getCategoryName()) * getCorrectRelation(waste.getEan().getUnit()) * waste.getAmount());
+        }
+        return getAnnualAveragePerPerson(CO2,number,timestamp);
+    }
+
+
+    /**
+     * Returns the amount of CO2 emissions per kg for a given category of waste.
+     * @param category the waste category
+     * @return the amount of CO2 emissions per kg
+     */
+    private static double getCO2ByCategory(String category){
+        switch (category){
+            case "meat, fish and chicken" -> {
+                return CO2_KG_MEAT;
+            }
+            case "baked goods and grains" -> {
+                return CO2_KG_BAKED;
+            }
+            case "dairy and egg" ->{
+                return CO2_KG_DAIRY;
+            }
+            case "fruit and vegetables" ->{
+                return CO2_KG_VEGETABLE;
+            }
+            default -> {
+                return CO2_KG_OTHER;
+            }
+        }
+    }
+
+    /**
+     * Returns the correct CO2 relation for a given unit of waste.
+     * @param unit the unit of waste
+     * @return the correct CO2 relation
+     */
+    private static double getCorrectRelation(String unit){
+        switch (unit){
+            case "l" -> {
+                return 0.998;
+            }
+            case "kg" -> {
+                return 1.0;
+            }
+            case "g" -> {
+                return 0.001;
+            }
+            case "ml" -> {
+                return 0.000998;
+            }
+            case "cl" -> {
+                return 0.00998;
+            }
+            case "dl" -> {
+                return 0.0998;
+            }
+            default -> {
+                return 0.1;
+            }
+        }
+    }
+
     /**
      * Get the annual average amount of CO2 emissions per person.
      *
@@ -19,13 +107,13 @@ public class StatisticUtil {
      * @param firstDate The date on which the group started tracking their CO2 emissions.
      * @return The annual average amount of CO2 emissions per person.
      */
-    private static double getAnnualAveragePerPerson(List<Double> co2List, int numberOfPerson, Date firstDate) {
+    private static double getAnnualAveragePerPerson(List<Double> co2List, int numberOfPerson, Timestamp firstDate) {
         java.util.Date currentDate = new java.util.Date();
         long diffInMillis = currentDate.getTime() - firstDate.getTime();
         long diffInDays = diffInMillis / (24 * 60 * 60 * 1000);
         double co2Sum = 0.0;
         for (double c02 : co2List) co2Sum += c02;
-        return co2Sum / (((double) diffInDays / 365.0) * (double) numberOfPerson);
+        return co2Sum / (((double) (diffInDays +1) / 365.0) * (double) numberOfPerson);
     }
 
     /**
@@ -47,4 +135,96 @@ public class StatisticUtil {
         }
         return numberOfWastes;
     }
+
+    /**
+     * Calculates the sum of waste for each of the four previous months.
+     * The amount of waste is converted to kilograms if the unit is in liters, grams, milliliters, centiliters, or deciliters.
+     *
+     * @param wastes the list of wastes to calculate the sum from
+     * @return an array of four doubles representing the sum of waste for each of the last four months,
+     *         in the same order as the months are counted backwards from the current month
+     */
+    public static double[] getNumberOfWasteByLastMonth(List<Waste> wastes){
+        double[] result = new double[4];
+        HashMap<Integer,List<Waste>> hashMap = new HashMap<>();
+
+        LocalDate localDate = LocalDate.now();
+        int currentMonth = localDate.getMonthValue();
+        int currentYear = localDate.getYear();
+        for(Waste waste : wastes){
+            LocalDate localDate1 = waste.getTimestamp().toLocalDateTime().toLocalDate();
+            if(currentMonth == localDate1.getMonthValue() && currentYear == localDate1.getYear()){
+                hashMap.computeIfAbsent(0, k -> new ArrayList<>());
+                hashMap.get(0).add(waste);
+            }
+            if(Math.abs((currentMonth-1) % 12) == localDate1.getMonthValue() && currentYear == localDate1.getYear()){
+                hashMap.computeIfAbsent(1, k -> new ArrayList<>());
+                hashMap.get(1).add(waste);
+            }
+            if(Math.abs((currentMonth-2) % 12) == localDate1.getMonthValue() && currentYear == localDate1.getYear()){
+                hashMap.computeIfAbsent(2, k -> new ArrayList<>());
+                hashMap.get(2).add(waste);
+            }
+            if(Math.abs((currentMonth-3) % 12) == localDate1.getMonthValue() && currentYear == localDate1.getYear()){
+                hashMap.computeIfAbsent(3, k -> new ArrayList<>());
+                hashMap.get(3).add(waste);
+            }
+        }
+        for(int i = 0; i < 4; i++){
+            result[i] = getSumOfWaste(hashMap.get(i));
+        }
+        return result;
+    }
+
+    /**
+     * Calculates the sum of waste for a list of wastes, and converts the amounts to kilograms if the unit is in liters,
+     * grams, milliliters, centiliters, or deciliters.
+     *
+     * @param wastes the list of wastes to calculate the sum from
+     * @return the sum of waste in kilograms
+     */
+    private static double getSumOfWaste(List<Waste> wastes){
+        double sum = 0.0;
+        if(wastes == null){
+            wastes = new ArrayList<>();
+        }
+        for(Waste waste: wastes){
+            sum += getCorrectRelation(waste.getEan().getUnit()) * waste.getAmount();
+        }
+        return sum;
+    }
+
+    /**
+     * Calculates the total amount of money lost due to expired or discarded items in the last 30 days,
+     * based on the list of wastes passed as a parameter.
+     *
+     * @param wastes the list of wastes to be analyzed
+     * @return the total amount of money lost due to expired or discarded items in the last 30 days
+     */
+    public static double getLostMoneyInLastMonth(List<Waste> wastes){
+        List<Waste> wasteList = new ArrayList<>();
+        LocalDateTime time = LocalDateTime.now().minusDays(30);
+        for(Waste waste: wastes){
+            if(waste.getTimestamp().after(Timestamp.valueOf(time))){
+                wasteList.add(waste);
+            }
+        }
+        return lostMoney(wasteList);
+    }
+
+    /**
+     * Calculates the total amount of money lost due to expired or discarded items,
+     * based on the list of wastes passed as a parameter.
+     *
+     * @param wastes the list of wastes to be analyzed
+     * @return the total amount of money lost due to expired or discarded items
+     */
+    private static double lostMoney(List<Waste> wastes){
+        double sum = 0.0;
+        for(Waste waste: wastes){
+            sum += waste.getAmount()*waste.getBuyPrice();
+        }
+        return sum;
+    }
+
 }
\ No newline at end of file
diff --git a/src/test/java/ntnu/idatt2016/v233/SmartMat/repository/group/GroupRepositoryTest.java b/src/test/java/ntnu/idatt2016/v233/SmartMat/repository/group/GroupRepositoryTest.java
index 69cd0518cdf81c5e27d83ebd15410faa43b321d7..52d6a2934e28d1f12f1083f67fc1dbdcc7218f1d 100644
--- a/src/test/java/ntnu/idatt2016/v233/SmartMat/repository/group/GroupRepositoryTest.java
+++ b/src/test/java/ntnu/idatt2016/v233/SmartMat/repository/group/GroupRepositoryTest.java
@@ -106,24 +106,22 @@ public class GroupRepositoryTest {
 
     @Test
     void groupShouldHaveAchivments(){
-        Optional<Group> tempGroupe = groupRepository.findByGroupName("test");
-
-
-        assertTrue(tempGroupe.isPresent());
 
+        Group tempgroup = Group.builder().groupName("testiossxjak").build();
         Achievement tempAchievement = Achievement.builder().achievementName("test2").build();
-        Group tempGroup = tempGroupe.get();
 
+        tempgroup.setAchievements(new ArrayList<>(Collections.singletonList(tempAchievement)));
+        groupRepository.save(tempgroup);
 
-        tempGroup.setAchievements(new ArrayList<>(Collections.singletonList(tempAchievement)));
+        Optional<Group> tempGroupe = groupRepository.findByGroupName("testiossxjak");
 
-        groupRepository.save(tempGroup);
 
-        assertTrue(groupRepository.findByGroupName("test").isPresent());
+        assertTrue(tempGroupe.isPresent());
+
 
-        assertTrue(groupRepository.findByGroupName("test").get().getAchievements().contains(tempAchievement));
+        assertTrue(tempGroupe.get().getAchievements().contains(tempAchievement));
 
-        assertNull(groupRepository.findByGroupName("test").get().getAchievements().get(0).getGroups());
+        assertNull(tempGroupe.get().getAchievements().get(0).getGroups());
 
     }
 
diff --git a/src/test/java/ntnu/idatt2016/v233/SmartMat/service/product/ProductServiceTest.java b/src/test/java/ntnu/idatt2016/v233/SmartMat/service/product/ProductServiceTest.java
index 3e63f644f1131ff2d1d222386beaa6398b00a65c..42595c72ca2cd9065873429645914e5d5c1b9810 100644
--- a/src/test/java/ntnu/idatt2016/v233/SmartMat/service/product/ProductServiceTest.java
+++ b/src/test/java/ntnu/idatt2016/v233/SmartMat/service/product/ProductServiceTest.java
@@ -134,7 +134,7 @@ public class ProductServiceTest {
         // Verify that the service returns the correct volume
         Optional<List<String>> returnedVolume = productService.getProductVolume(productId);
         assertTrue(returnedVolume.isPresent());
-        assertEquals(List.of("500", "ml"), returnedVolume.get());
+        assertEquals(List.of("500.0", "ml"), returnedVolume.get());
     }
 
     @Test
diff --git a/src/test/java/ntnu/idatt2016/v233/SmartMat/util/ProductUtilTest.java b/src/test/java/ntnu/idatt2016/v233/SmartMat/util/ProductUtilTest.java
index 0164ae29d869b4a85b47dab4cdd82d95c78d8b1e..2ee4467a78d2727454b1cd6a497527973dca9bac 100644
--- a/src/test/java/ntnu/idatt2016/v233/SmartMat/util/ProductUtilTest.java
+++ b/src/test/java/ntnu/idatt2016/v233/SmartMat/util/ProductUtilTest.java
@@ -22,7 +22,7 @@ class ProductUtilTest {
 
     @Test
     void getVolumeFromProduct() {
-        assertEquals(List.of("24x500", "ml"), ProductUtil.getVolumeFromProduct(product).get());
+        assertEquals(List.of("500.0", "ml"), ProductUtil.getVolumeFromProduct(product).get());
 
         this.product = Product.builder()
                 .ean(123456789)
@@ -30,7 +30,7 @@ class ProductUtilTest {
                 .description("Pepsi Original 24x500 ml")
                 .build();
 
-        assertEquals(List.of("24x500", "ml"), ProductUtil.getVolumeFromProduct(product).get());
+        assertEquals(List.of("500.0", "ml"), ProductUtil.getVolumeFromProduct(product).get());
 
         this.product = Product.builder()
                 .ean(123456789)
@@ -39,7 +39,7 @@ class ProductUtilTest {
                 .build();
 
 
-        assertEquals(List.of("24x500", "ml"), ProductUtil.getVolumeFromProduct(product).get());
+        assertEquals(List.of("500.0", "ml"), ProductUtil.getVolumeFromProduct(product).get());
 
         this.product = Product.builder()
                 .ean(123456789)
@@ -48,6 +48,6 @@ class ProductUtilTest {
                 .build();
 
 
-        assertEquals(List.of("24x500", "ml"), ProductUtil.getVolumeFromProduct(product).get());
+        assertEquals(List.of("500.0", "ml"), ProductUtil.getVolumeFromProduct(product).get());
     }
 }
\ No newline at end of file
diff --git a/src/test/java/ntnu/idatt2016/v233/SmartMat/util/StatisticUtils.java b/src/test/java/ntnu/idatt2016/v233/SmartMat/util/StatisticUtils.java
index 3560688c40d2613caf1228f2cfaf11227920866f..fd7f879b95f0162ffc037c36b0b17fb60b5d9f7c 100644
--- a/src/test/java/ntnu/idatt2016/v233/SmartMat/util/StatisticUtils.java
+++ b/src/test/java/ntnu/idatt2016/v233/SmartMat/util/StatisticUtils.java
@@ -1,11 +1,6 @@
 package ntnu.idatt2016.v233.SmartMat.util;
 
 public class StatisticUtils {
-    private final static double CO2_KG_MEAT = (99.48 + 39.72 + 33.3 + 26.87 + 12.31 + 9.87 )/6.0;
-    private final static double CO2_KG_DAIRY = (23.88 + 4.67 + 3.15)/3;
-    private final static double CO2_KG_BAKED = (4.45 + 1.7 + 1.57)/3;
-    private final static double CO2_KG_VEGETABLE = (2.09 + 0.98 + 0.86 + 0.46)/4;
 
-    private final static double CO2_KG_OTHER = (CO2_KG_MEAT + CO2_KG_DAIRY  + CO2_KG_BAKED + CO2_KG_VEGETABLE)/4.0;
     
 }