/*
 * File: src/main/java/reports/service/PurchaseService.java
 * Description: This service class provides functionality for handling purchase-related operations in the ERP reporting system.
 * It includes methods for retrieving KPI data and generating purchase reports.
 */

package com.nebula.erp.reports.service;

import com.nebula.erp.reports.model.purchase.*;
import com.nebula.erp.reports.repository.product.BrandRepository;
import com.nebula.erp.reports.repository.product.CategoryRepository;
import com.nebula.erp.reports.repository.purchase.*;
import com.nebula.erp.reports.repository.sales.SalesRepository;
import com.nebula.erp.reports.repository.sales.SalesReturnItemRepository;
import com.nebula.erp.reports.repository.sales.SalesItemRepository;
import com.nebula.erp.reports.repository.product.ProductRepository;
import com.nebula.erp.reports.requestmodel.PurchaseRequest;
import com.nebula.erp.reports.utility.CreateLogger;
import com.nebula.erp.reports.utility.JwtRequestUtils;
import com.nebula.erp.reports.utility.MoneyUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import com.nebula.erp.reports.utility.ApiResponseStructure;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class PurchaseService {

    @Autowired
    private PurchaseRepository purchaseRepository;

    @Autowired
    private SalesRepository salesRepository;

    @Autowired
    private SalesItemRepository salesItemRepository;

    @Autowired
    private SalesReturnItemRepository salesReturnItemRepository;

    @Autowired
    private SupplierRepository supplierRepository;

    @Autowired
    private GRNRepository grnRepository;

    @Autowired
    private PurchaseReturnRepository purchaseReturnRepository;

    @Autowired
    private PurchaseReturnItemRepository purchaseReturnItemRepository;

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private GRNItemRepository grnItemRepository;

    @Autowired
    private PurchaseItemRepository purchaseItemRepository;

    @Autowired
    private CategoryRepository categoryRepository;

    @Autowired
    private BrandRepository brandRepository;

    @Autowired
    private JwtRequestUtils jwtRequestUtils;

    @Autowired
    private HttpServletRequest httpServletRequest;

    @Autowired
    private CreateLogger createLogger;

    private static final String path = "/reports/purchase";

    public ApiResponseStructure <Map<String, Object>> getKPIData(LocalDate fromDate, LocalDate toDate) {

        // Extract Authorization headers from the request
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.AUTHORIZATION, httpServletRequest.getHeader(HttpHeaders.AUTHORIZATION));

        String tenantName = jwtRequestUtils.getTenantNameFromHeaders(headers);

        if (fromDate != null && toDate != null){

            // Convert LocalDate to LocalDateTime for comparison with created_at
            LocalDateTime fromDateTime = fromDate.atStartOfDay();
            LocalDateTime toDateTime = toDate.atTime(23, 59, 59);

            Long totalPurchaseOrder = purchaseRepository.countPurchasesByDateRangeAndTenant(fromDateTime, toDateTime, tenantName);
            Long totalReceivedQuantity = grnItemRepository.sumQuantityFromGRNItems(fromDateTime, toDateTime, tenantName);
            List<Long> supplierIds = purchaseRepository.findSupplierWithMostPurchases(fromDateTime, toDateTime, tenantName);
            Long topSupplierId = supplierIds.isEmpty() ? null : supplierIds.get(0);
            String topSupplierName = null;
            if (topSupplierId != null) {
                topSupplierName = supplierRepository.findSupplierNameById(supplierIds.get(0), tenantName);
            }
            Double averagePurchaseValue = grnItemRepository.averageTotalPrice(fromDateTime, toDateTime, tenantName);
            Long totalSuppliers = supplierRepository.countTotalSuppliersForTenant(tenantName, fromDateTime, toDateTime);

            // Create the response map
            Map<String, Object> purchaseData = new LinkedHashMap<>();
            purchaseData.put("total_purchase_order", totalPurchaseOrder);
            purchaseData.put("total_received_quantity", totalReceivedQuantity);
            purchaseData.put("top_supplier_by_orders", topSupplierName);
            purchaseData.put("average_purchase_value", MoneyUtils.truncateToTwoDecimals(averagePurchaseValue));
            purchaseData.put("total_suppliers", totalSuppliers);

            // Create and return the structured ApiResponseStructure
            return new ApiResponseStructure<>("Success", 200, "Data retrieved.", purchaseData);
        }
        createLogger.createLogger("error", path, "GET", "Please provide start-date and end-date with valid dates.", "");
        return new ApiResponseStructure<>("Failure", 500, "Please provide start-date and end-date with valid dates.", Collections.emptyMap());
    }

    public ApiResponseStructure <Map<String, Object>> getPurchaseReport(PurchaseRequest purchaseRequest, String reportType){
        // Extract Authorization headers from the request
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.AUTHORIZATION, httpServletRequest.getHeader(HttpHeaders.AUTHORIZATION));

        String tenantName = jwtRequestUtils.getTenantNameFromHeaders(headers);

        // Validate presence of fromDate and toDate
        if (purchaseRequest.getStartDate() == null || purchaseRequest.getEndDate() == null) {
            createLogger.createLogger("error", path, "POST", "Both 'startDate' and 'endDate' must be provided.", "");
            return new ApiResponseStructure<>("Error", HttpStatus.BAD_REQUEST.value(), "Both 'startDate' and 'endDate' must be provided.", new HashMap<>());
        }

        // Create a specification for the query
        Specification<GRNItem> spec = Specification.where(null);

        // Add tenant name filtering
        spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("tenant"), tenantName));

        // Check the data types for getStartDate() and getEndDate()
        LocalDate fromDate = purchaseRequest.getStartDate(); // Ensure this is LocalDate
        LocalDate toDate = purchaseRequest.getEndDate();     // Ensure this is LocalDate

        // Convert LocalDate to LocalDateTime
        LocalDateTime fromDateTime = fromDate.atStartOfDay();
        LocalDateTime toDateTime = toDate.atTime(23, 59, 59);

        // Add date range filtering
        if (purchaseRequest.getStartDate() != null && purchaseRequest.getEndDate() != null) {
            spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.between(root.get("created_at"), fromDateTime, toDateTime));
        }

        // Switch cases to handle various report type
        switch (reportType) {
            case "bySupplier":
                // Add dynamic conditions
                if (purchaseRequest.getConditions() != null) {
                    for (PurchaseRequest.Condition condition : purchaseRequest.getConditions()) {
                        switch (condition.getOperator()) {
                            case "equals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(condition.getField()), condition.getValue()));
                                break;
                            case "greaterThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "greaterThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            default:
                                createLogger.createLogger("error", path, "POST", "", "");
                                throw new IllegalArgumentException("Operator " + condition.getOperator() + " is not supported.");
                        }
                    }
                }

                // Fetch the data with pagination for GRN items
                Pageable pageable = PageRequest.of(purchaseRequest.getPage() != null ? purchaseRequest.getPage() : 0, // Page number is zero-based
                        purchaseRequest.getSize() != null ? purchaseRequest.getSize() : 20);

                // Fetch all GRNItems based on the specification
                Page<GRNItem> grnItemPage = grnItemRepository.findAll(spec, pageable);

                // Group purchases by supplier
                Map<Long, Map<String, Object>> groupedPurchaseData = new HashMap<>();

                // Iterate through each GRNItem and accumulate quantities and total prices
                grnItemPage.getContent().forEach(item -> {
                    Long supplierId = item.getGrn_item().getSupplier().getId(); // Get supplier ID from GRN
                    String supplierName = item.getGrn_item().getSupplier().getSupplier_name(); // Get supplier name from GRN

                    // Compute and initialize supplier data if it doesn't exist
                    groupedPurchaseData.computeIfAbsent(supplierId, id -> {
                        Map<String, Object> data = new LinkedHashMap<>();
                        data.put("supplier_id", supplierId);
                        data.put("supplier_name", supplierName);
                        data.put("total_quantity", 0);
                        data.put("total_price", 0.00);
                        data.put("purchases", new ArrayList<>()); // Initialize purchases array
                        return data;
                    });

                    // Update totals
                    Map<String, Object> data = groupedPurchaseData.get(supplierId);
                    data.put("total_quantity", (Integer) data.get("total_quantity") + item.getQuantity());
                    data.put("total_price", MoneyUtils.truncateToTwoDecimals((Double) data.get("total_price") + item.getTotal_price()));
                    //data.put("total_price", (Double.valueOf((String) data.get("total_price"))).add(item.getTotal_price())); // Sum total price

                    // Prepare purchase item details
                    Map<String, Object> purchaseItemDetails = new LinkedHashMap<>();
                    purchaseItemDetails.put("product_id", item.getProduct_id());
                    String productName = productRepository.findProductNameById(item.getProduct_id(), tenantName);
                    Long categoryId = productRepository.findCategoryIdByProductId(item.getProduct_id(), tenantName); // Fetch category ID
                    Long brandId = productRepository.findBrandIdByProductId(item.getProduct_id(), tenantName); // Fetch brand ID
                    String categoryName = categoryRepository.findCategoryNameById(categoryId, tenantName); // Fetch category name
                    String brandName = brandRepository.findBrandNameById(brandId, tenantName); // Fetch brand name
                    purchaseItemDetails.put("product_name", productName);
                    purchaseItemDetails.put("category_id", categoryId);
                    purchaseItemDetails.put("category_name", categoryName);
                    purchaseItemDetails.put("brand_id", brandId);
                    purchaseItemDetails.put("brand_name", brandName);
                    purchaseItemDetails.put("quantity", item.getQuantity());
                    purchaseItemDetails.put("total_price", MoneyUtils.truncateToTwoDecimals(item.getTotal_price()));
                    purchaseItemDetails.put("unit_price", item.getUnit_price());

                    // Add purchase item details to the purchases array
                    List<Map<String, Object>> purchases = (List<Map<String, Object>>) data.get("purchases");
                    purchases.add(purchaseItemDetails);
                });

                // Prepare reportData list from the grouped data
                List<Map<String, Object>> purchaseDataList = new ArrayList<>(groupedPurchaseData.values());

                // Prepare column details
                Map<String, Object> column = new LinkedHashMap<>();
                column.put("supplier_id", "SUPPLIER ID");
                column.put("supplier_name", "SUPPLIER NAME");
                column.put("total_quantity", "TOTAL QUANTITY");
                column.put("total_price", "TOTAL PRICE");
                column.put("product_id", "PRODUCT ID");
                column.put("product_name", "PRODUCT NAME");
                column.put("category_id", "CATEGORY ID");
                column.put("category_name", "CATEGORY NAME");
                column.put("brand_id", "BRAND ID");
                column.put("brand_name", "BRAND NAME");
                column.put("quantity", "QUANTITY");
                column.put("unit_price", "UNIT PRICE");

                // Prepare pagination details
                Map<String, Object> pagination = new LinkedHashMap<>();
                pagination.put("currentPage", grnItemPage.getNumber() + 1); // Page number is 0-based
                pagination.put("totalPages", grnItemPage.getTotalPages());
                pagination.put("pageSize", pageable.getPageSize());
                pagination.put("totalRecords", groupedPurchaseData.size());

                // Calculate summary details
                double totalRevenue = purchaseDataList.stream().mapToDouble(data -> (Double) data.get("total_price")).sum();

                int totalItemsSold = purchaseDataList.stream().mapToInt(data -> (Integer) data.get("total_quantity")).sum();

                // Find the top supplier based on total purchases
                Map<Long, Integer> supplierPurchaseMap = new HashMap<>();
                purchaseDataList.forEach(data -> {
                    Long supplierId = (Long) data.get("supplier_id");
                    Integer quantity = (Integer) data.get("total_quantity");
                    supplierPurchaseMap.put(supplierId, supplierPurchaseMap.getOrDefault(supplierId, 0) + quantity);
                });

                Long topSupplierId = supplierPurchaseMap.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);

                String topSupplierName = null;
                if (topSupplierId != null) {
                    topSupplierName = supplierRepository.findSupplierNameById(topSupplierId, tenantName); // Assuming a method exists to get supplier name by ID
                }

                // Prepare summary details
                Map<String, Object> summary = new LinkedHashMap<>();
                summary.put("totalRevenue", MoneyUtils.truncateToTwoDecimals(totalRevenue));
                summary.put("totalItemsSold", totalItemsSold);
                summary.put("topSupplier", topSupplierName);

                // Prepare response data
                Map<String, Object> purchaseData = new LinkedHashMap<>();
                purchaseData.put("module", "purchase");
                purchaseData.put("reportType", reportType);
                purchaseData.put("startDate", String.valueOf(fromDate));
                purchaseData.put("endDate", String.valueOf(toDate));
                purchaseData.put("reportData", purchaseDataList);
                purchaseData.put("column", column);
                purchaseData.put("pagination", pagination);
                purchaseData.put("summary", summary);

                // Create and return the structured ApiResponseStructure
                return new ApiResponseStructure<>("Success", 200, "Data retrieved.", purchaseData);
            case "byCategory":
                // Add dynamic conditions
                if (purchaseRequest.getConditions() != null) {
                    for (PurchaseRequest.Condition condition : purchaseRequest.getConditions()) {
                        switch (condition.getOperator()) {
                            case "equals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(condition.getField()), condition.getValue()));
                                break;
                            case "greaterThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "greaterThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            default:
                                createLogger.createLogger("error", path, "POST", "", "");
                                throw new IllegalArgumentException("Operator " + condition.getOperator() + " is not supported.");
                        }
                    }
                }

                // Fetch the data with pagination for GRN items
                pageable = PageRequest.of(purchaseRequest.getPage() != null ? purchaseRequest.getPage() : 0, // Page number is zero-based
                        purchaseRequest.getSize() != null ? purchaseRequest.getSize() : 20);

                // Fetch all GRNItems based on the specification
                grnItemPage = grnItemRepository.findAll(spec, pageable);

                // Group GRN items by category_id
                Map<Long, Map<String, Object>> groupedGRNDataByCategory = new HashMap<>();

                grnItemPage.getContent().forEach(item -> {
                    Long categoryId = productRepository.findCategoryIdByProductId(item.getProduct_id(), tenantName); // Get category ID from product
                    Long brandId = productRepository.findBrandIdByProductId(item.getProduct_id(), tenantName); // Get brand ID from product
                    String categoryName = categoryRepository.findCategoryNameById(categoryId, tenantName); // Get category name
                    String brandName = brandRepository.findBrandNameById(brandId, tenantName); // Get brand name
                    String productName = productRepository.findProductNameById(item.getProduct_id(), tenantName); // Get product name

                    // Create a new entry for the category if it doesn't exist
                    groupedGRNDataByCategory.computeIfAbsent(categoryId, id -> {
                        Map<String, Object> data = new LinkedHashMap<>();
                        data.put("category_id", categoryId);
                        data.put("category_name", categoryName);
                        data.put("brand_id", brandId);
                        data.put("brand_name", brandName);
                        data.put("total_quantity", 0);
                        data.put("total_price", 0.00);
                        data.put("grn_items", new ArrayList<Map<String, Object>>()); // Initialize GRN items array
                        return data;
                    });

                    // Update totals
                    Map<String, Object> data = groupedGRNDataByCategory.get(categoryId);
                    data.put("total_quantity", (Integer) data.get("total_quantity") + item.getQuantity());
                    data.put("total_price", MoneyUtils.truncateToTwoDecimals((Double) data.get("total_price") + item.getTotal_price())); // Sum total price

                    // Prepare GRN item details to add to the GRN items array
                    Map<String, Object> grnItemData = new LinkedHashMap<>();
                    grnItemData.put("product_id", item.getProduct_id());
                    grnItemData.put("product_name", productName);
                    grnItemData.put("category_id", categoryId);
                    grnItemData.put("category_name", categoryName);
                    grnItemData.put("brand_id", brandId);
                    grnItemData.put("brand_name", brandName);
                    grnItemData.put("quantity", item.getQuantity());
                    grnItemData.put("total_price", MoneyUtils.truncateToTwoDecimals(item.getTotal_price()));
                    grnItemData.put("unit_price", item.getUnit_price());

                    List<Map<String, Object>> grnItemsList = (List<Map<String, Object>>) data.get("grn_items");
                    grnItemsList.add(grnItemData); // Add the GRN item details to the list
                });

                // Prepare reportData list from the grouped data
                List<Map<String, Object>> grnDataListByCategory = new ArrayList<>(groupedGRNDataByCategory.values());

                // Prepare column details
                column = new LinkedHashMap<>();
                column.put("product_id", "PRODUCT ID");
                column.put("product_name", "PRODUCT NAME");
                column.put("category_id", "CATEGORY ID");
                column.put("category_name", "CATEGORY NAME");
                column.put("brand_id", "BRAND ID");
                column.put("brand_name", "BRAND NAME");
                column.put("total_quantity", "TOTAL QUANTITY");
                column.put("total_price", "TOTAL PRICE");

                // Prepare pagination details
                pagination = new LinkedHashMap<>();
                pagination.put("currentPage", grnItemPage.getNumber() + 1); // Page number is 0-based
                pagination.put("totalPages", grnItemPage.getTotalPages());
                pagination.put("pageSize", pageable.getPageSize());
                pagination.put("totalRecords", groupedGRNDataByCategory.size());

                // Calculate summary details
                totalRevenue = grnDataListByCategory.stream().mapToDouble(data -> (Double) data.get("total_price")).sum();

                totalItemsSold = grnDataListByCategory.stream().mapToInt(data -> (Integer) data.get("total_quantity")).sum();

                // Find the top purchased category based on total quantities
                Map<Long, Integer> categorySalesMap = new HashMap<>();
                grnDataListByCategory.forEach(data -> {
                    Long categoryId = (Long) data.get("category_id");
                    Integer quantity = (Integer) data.get("total_quantity");
                    categorySalesMap.put(categoryId, categorySalesMap.getOrDefault(categoryId, 0) + quantity);
                });

                Long topPurchasedCategoryId = categorySalesMap.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);

                // Fetch the category name using the topPurchasedCategoryId
                String topPurchasedCategoryName = null;
                if (topPurchasedCategoryId != null) {
                    topPurchasedCategoryName = categoryRepository.findCategoryNameById(topPurchasedCategoryId, tenantName); // Adjust this line as needed
                }

                // Prepare summary details
                summary = new LinkedHashMap<>();
                summary.put("totalRevenue", MoneyUtils.truncateToTwoDecimals(totalRevenue));
                summary.put("totalItemsSold", totalItemsSold);
                summary.put("topPurchasedCategory", topPurchasedCategoryName); // Add top purchased category

                // Prepare response data
                Map<String, Object> grnData = new LinkedHashMap<>();
                grnData.put("module", "purchase");
                grnData.put("reportType", reportType);
                grnData.put("startDate", String.valueOf(fromDate));
                grnData.put("endDate", String.valueOf(toDate));
                grnData.put("reportData", grnDataListByCategory);
                grnData.put("column", column);
                grnData.put("pagination", pagination);
                grnData.put("summary", summary);

                // Create and return the structured ApiResponseStructure
                return new ApiResponseStructure<>("Success", 200, "Data retrieved.", grnData);
            case "byProduct":
                // Add dynamic conditions
                if (purchaseRequest.getConditions() != null) {
                    for (PurchaseRequest.Condition condition : purchaseRequest.getConditions()) {
                        switch (condition.getOperator()) {
                            case "equals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(condition.getField()), condition.getValue()));
                                break;
                            case "greaterThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "greaterThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            default:
                                createLogger.createLogger("error", path, "POST", "", "");
                                throw new IllegalArgumentException("Operator " + condition.getOperator() + " is not supported.");
                        }
                    }
                }

                // Fetch the data with pagination for GRN items
                pageable = PageRequest.of(purchaseRequest.getPage() != null ? purchaseRequest.getPage() : 0, // Page number is zero-based
                        purchaseRequest.getSize() != null ? purchaseRequest.getSize() : 20);

                // Fetch all GRNItems based on the specification
                grnItemPage = grnItemRepository.findAll(spec, pageable);

                // Group GRN items by product_id
                Map<Long, Map<String, Object>> groupedGRNDataByProduct = new HashMap<>();

                // Iterate through each GRNItem and accumulate quantities and total prices
                grnItemPage.getContent().forEach(item -> {
                    Long productId = item.getProduct_id(); // Get product ID
                    String productName = productRepository.findProductNameById(productId, tenantName); // Fetch product name
                    Long categoryId = productRepository.findCategoryIdByProductId(productId, tenantName); // Fetch category ID
                    Long brandId = productRepository.findBrandIdByProductId(productId, tenantName); // Fetch brand ID
                    String categoryName = categoryRepository.findCategoryNameById(categoryId, tenantName); // Fetch category name
                    String brandName = brandRepository.findBrandNameById(brandId, tenantName); // Fetch brand name

                    // Create a new entry for the product if it doesn't exist
                    groupedGRNDataByProduct.computeIfAbsent(productId, id -> {
                        Map<String, Object> data = new LinkedHashMap<>();
                        data.put("product_id", productId);
                        data.put("product_name", productName);
                        data.put("category_id", categoryId);
                        data.put("category_name", categoryName);
                        data.put("brand_id", brandId);
                        data.put("brand_name", brandName);
                        data.put("quantity", 0);
                        data.put("total_price", 0.00);
                        return data;
                    });

                    // Get the current data for the product
                    Map<String, Object> data = groupedGRNDataByProduct.get(productId);
                    data.put("quantity", (Integer) data.get("quantity") + item.getQuantity());
                    data.put("total_price", MoneyUtils.truncateToTwoDecimals((Double) data.get("total_price") + item.getTotal_price())); // Sum total price
                });

                // Prepare reportData list from the grouped data
                List<Map<String, Object>> grnDataListByProduct = new ArrayList<>(groupedGRNDataByProduct.values());

                // Prepare column details
                column = new LinkedHashMap<>();
                column.put("product_id", "PRODUCT ID");
                column.put("product_name", "PRODUCT NAME");
                column.put("category_id", "CATEGORY ID");
                column.put("category_name", "CATEGORY NAME");
                column.put("brand_id", "BRAND ID");
                column.put("brand_name", "BRAND NAME");
                column.put("quantity", "QUANTITY");
                column.put("total_price", "TOTAL PRICE");

                // Prepare pagination details
                pagination = new LinkedHashMap<>();
                pagination.put("currentPage", grnItemPage.getNumber() + 1); // Page number is 0-based
                pagination.put("totalPages", grnItemPage.getTotalPages());
                pagination.put("pageSize", pageable.getPageSize());
                pagination.put("totalRecords", groupedGRNDataByProduct.size());

                // Calculate summary details
                totalRevenue = grnDataListByProduct.stream().mapToDouble(data -> (Double) data.get("total_price")).sum();

                totalItemsSold = grnDataListByProduct.stream().mapToInt(data -> (Integer) data.get("quantity")).sum();

                // Find the top purchased product based on total quantity
                Map<Long, Integer> productSalesMap = new HashMap<>();
                grnDataListByProduct.forEach(data -> {
                    Long productId = (Long) data.get("product_id");
                    Integer quantity = (Integer) data.get("quantity");
                    productSalesMap.put(productId, productSalesMap.getOrDefault(productId, 0) + quantity);
                });

                Long topPurchasedProductId = productSalesMap.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);

                String topPurchasedProductName = null;
                if (topPurchasedProductId != null) {
                    topPurchasedProductName = productRepository.findProductNameById(topPurchasedProductId, tenantName); // Fetch the top product name
                }

                // Prepare summary details
                summary = new LinkedHashMap<>();
                summary.put("totalRevenue", MoneyUtils.truncateToTwoDecimals(totalRevenue));
                summary.put("totalItemsSold", totalItemsSold);
                summary.put("topPurchasedProduct", topPurchasedProductName);

                // Prepare response data
                grnData = new LinkedHashMap<>();
                grnData.put("module", "purchase");
                grnData.put("reportType", reportType);
                grnData.put("startDate", String.valueOf(fromDate));
                grnData.put("endDate", String.valueOf(toDate));
                grnData.put("reportData", grnDataListByProduct);
                grnData.put("column", column);
                grnData.put("pagination", pagination);
                grnData.put("summary", summary);

                // Create and return the structured ApiResponseStructure
                return new ApiResponseStructure<>("Success", 200, "Data retrieved.", grnData);
            case "daily":
                // Add dynamic conditions
                if (purchaseRequest.getConditions() != null) {
                    for (PurchaseRequest.Condition condition : purchaseRequest.getConditions()) {
                        switch (condition.getOperator()) {
                            case "equals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(condition.getField()), condition.getValue()));
                                break;
                            case "greaterThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "greaterThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            default:
                                createLogger.createLogger("error", path, "POST", "", "");
                                throw new IllegalArgumentException("Operator " + condition.getOperator() + " is not supported.");
                        }
                    }
                }

                // Fetch the data with pagination for GRN items
                pageable = PageRequest.of(purchaseRequest.getPage() != null ? purchaseRequest.getPage() : 0, // Page number is zero-based
                        purchaseRequest.getSize() != null ? purchaseRequest.getSize() : 20);

                // Fetch all GRNItems based on the specification
                grnItemPage = grnItemRepository.findAll(spec, pageable);

                // Group GRN items by product_id
                groupedGRNDataByProduct = new HashMap<>();

                // Iterate through each GRNItem and accumulate quantities and total prices
                grnItemPage.getContent().forEach(item -> {
                    Long productId = item.getProduct_id(); // Get product ID
                    String productName = productRepository.findProductNameById(productId, tenantName); // Fetch product name
                    Long categoryId = productRepository.findCategoryIdByProductId(productId, tenantName); // Fetch category ID
                    Long brandId = productRepository.findBrandIdByProductId(productId, tenantName); // Fetch brand ID
                    String categoryName = categoryRepository.findCategoryNameById(categoryId, tenantName); // Fetch category name
                    String brandName = brandRepository.findBrandNameById(brandId, tenantName); // Fetch brand name

                    // Create a new entry for the product if it doesn't exist
                    groupedGRNDataByProduct.computeIfAbsent(productId, id -> {
                        Map<String, Object> data = new LinkedHashMap<>();
                        data.put("product_id", productId);
                        data.put("product_name", productName);
                        data.put("category_id", categoryId);
                        data.put("category_name", categoryName);
                        data.put("brand_id", brandId);
                        data.put("brand_name", brandName);
                        data.put("quantity", 0);
                        data.put("total_price", 0.00);
                        return data;
                    });

                    // Get the current data for the product
                    Map<String, Object> data = groupedGRNDataByProduct.get(productId);
                    data.put("quantity", (Integer) data.get("quantity") + item.getQuantity());
                    data.put("total_price", MoneyUtils.truncateToTwoDecimals((Double) data.get("total_price") + item.getTotal_price())); // Sum total price
                });

                // Prepare reportData list from the grouped data
                grnDataListByProduct = new ArrayList<>(groupedGRNDataByProduct.values());

                // Prepare column details
                column = new LinkedHashMap<>();
                column.put("product_id", "PRODUCT ID");
                column.put("product_name", "PRODUCT NAME");
                column.put("category_id", "CATEGORY ID");
                column.put("category_name", "CATEGORY NAME");
                column.put("brand_id", "BRAND ID");
                column.put("brand_name", "BRAND NAME");
                column.put("quantity", "QUANTITY");
                column.put("total_price", "TOTAL PRICE");

                // Prepare pagination details
                pagination = new LinkedHashMap<>();
                pagination.put("currentPage", grnItemPage.getNumber() + 1); // Page number is 0-based
                pagination.put("totalPages", grnItemPage.getTotalPages());
                pagination.put("pageSize", pageable.getPageSize());
                pagination.put("totalRecords", groupedGRNDataByProduct.size());

                // Calculate summary details
                totalRevenue = grnDataListByProduct.stream().mapToDouble(data -> (Double) data.get("total_price")).sum();

                totalItemsSold = grnDataListByProduct.stream().mapToInt(data -> (Integer) data.get("quantity")).sum();

                // Find the top purchased product based on total quantity
                productSalesMap = new HashMap<>();
                grnDataListByProduct.forEach(data -> {
                    Long productId = (Long) data.get("product_id");
                    Integer quantity = (Integer) data.get("quantity");
                    productSalesMap.put(productId, productSalesMap.getOrDefault(productId, 0) + quantity);
                });

                topPurchasedProductId = productSalesMap.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);

                topPurchasedProductName = null;
                if (topPurchasedProductId != null) {
                    topPurchasedProductName = productRepository.findProductNameById(topPurchasedProductId, tenantName); // Fetch the top product name
                }

                // Prepare summary details
                summary = new LinkedHashMap<>();
                summary.put("totalRevenue", MoneyUtils.truncateToTwoDecimals(totalRevenue));
                summary.put("totalItemsSold", totalItemsSold);
                summary.put("topPurchasedProduct", topPurchasedProductName);

                // Prepare response data
                grnData = new LinkedHashMap<>();
                grnData.put("module", "purchase");
                grnData.put("reportType", reportType);
                grnData.put("startDate", String.valueOf(fromDate));
                grnData.put("endDate", String.valueOf(toDate));
                grnData.put("reportData", grnDataListByProduct);
                grnData.put("column", column);
                grnData.put("pagination", pagination);
                grnData.put("summary", summary);

                // Create and return the structured ApiResponseStructure
                return new ApiResponseStructure<>("Success", 200, "Data retrieved.", grnData);
            case "monthly":
                // Add dynamic conditions
                if (purchaseRequest.getConditions() != null) {
                    for (PurchaseRequest.Condition condition : purchaseRequest.getConditions()) {
                        switch (condition.getOperator()) {
                            case "equals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(condition.getField()), condition.getValue()));
                                break;
                            case "greaterThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "greaterThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            default:
                                createLogger.createLogger("error", path, "POST", "", "");
                                throw new IllegalArgumentException("Operator " + condition.getOperator() + " is not supported.");
                        }
                    }
                }

                // Fetch the data with pagination for GRN items
                pageable = PageRequest.of(purchaseRequest.getPage() != null ? purchaseRequest.getPage() : 0, // Page number is zero-based
                        purchaseRequest.getSize() != null ? purchaseRequest.getSize() : 20);

                // Fetch all GRNItems based on the specification
                grnItemPage = grnItemRepository.findAll(spec, pageable);

                // Group GRN items by product_id
                groupedGRNDataByProduct = new HashMap<>();

                // Iterate through each GRNItem and accumulate quantities and total prices
                grnItemPage.getContent().forEach(item -> {
                    Long productId = item.getProduct_id(); // Get product ID
                    String productName = productRepository.findProductNameById(productId, tenantName); // Fetch product name
                    Long categoryId = productRepository.findCategoryIdByProductId(productId, tenantName); // Fetch category ID
                    Long brandId = productRepository.findBrandIdByProductId(productId, tenantName); // Fetch brand ID
                    String categoryName = categoryRepository.findCategoryNameById(categoryId, tenantName); // Fetch category name
                    String brandName = brandRepository.findBrandNameById(brandId, tenantName); // Fetch brand name

                    // Create a new entry for the product if it doesn't exist
                    groupedGRNDataByProduct.computeIfAbsent(productId, id -> {
                        Map<String, Object> data = new LinkedHashMap<>();
                        data.put("product_id", productId);
                        data.put("product_name", productName);
                        data.put("category_id", categoryId);
                        data.put("category_name", categoryName);
                        data.put("brand_id", brandId);
                        data.put("brand_name", brandName);
                        data.put("quantity", 0);
                        data.put("total_price", 0.00);
                        return data;
                    });

                    // Get the current data for the product
                    Map<String, Object> data = groupedGRNDataByProduct.get(productId);
                    data.put("quantity", (Integer) data.get("quantity") + item.getQuantity());
                    data.put("total_price", MoneyUtils.truncateToTwoDecimals((Double) data.get("total_price") + item.getTotal_price())); // Sum total price
                });

                // Prepare reportData list from the grouped data
                grnDataListByProduct = new ArrayList<>(groupedGRNDataByProduct.values());

                // Prepare column details
                column = new LinkedHashMap<>();
                column.put("product_id", "PRODUCT ID");
                column.put("product_name", "PRODUCT NAME");
                column.put("category_id", "CATEGORY ID");
                column.put("category_name", "CATEGORY NAME");
                column.put("brand_id", "BRAND ID");
                column.put("brand_name", "BRAND NAME");
                column.put("quantity", "QUANTITY");
                column.put("total_price", "TOTAL PRICE");

                // Prepare pagination details
                pagination = new LinkedHashMap<>();
                pagination.put("currentPage", grnItemPage.getNumber() + 1); // Page number is 0-based
                pagination.put("totalPages", grnItemPage.getTotalPages());
                pagination.put("pageSize", pageable.getPageSize());
                pagination.put("totalRecords", groupedGRNDataByProduct.size());

                // Calculate summary details
                totalRevenue = grnDataListByProduct.stream().mapToDouble(data -> (Double) data.get("total_price")).sum();

                totalItemsSold = grnDataListByProduct.stream().mapToInt(data -> (Integer) data.get("quantity")).sum();

                // Find the top purchased product based on total quantity
                productSalesMap = new HashMap<>();
                grnDataListByProduct.forEach(data -> {
                    Long productId = (Long) data.get("product_id");
                    Integer quantity = (Integer) data.get("quantity");
                    productSalesMap.put(productId, productSalesMap.getOrDefault(productId, 0) + quantity);
                });

                topPurchasedProductId = productSalesMap.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);

                topPurchasedProductName = null;
                if (topPurchasedProductId != null) {
                    topPurchasedProductName = productRepository.findProductNameById(topPurchasedProductId, tenantName); // Fetch the top product name
                }

                // Prepare summary details
                summary = new LinkedHashMap<>();
                summary.put("totalRevenue", MoneyUtils.truncateToTwoDecimals(totalRevenue));
                summary.put("totalItemsSold", totalItemsSold);
                summary.put("topPurchasedProduct", topPurchasedProductName);

                // Prepare response data
                grnData = new LinkedHashMap<>();
                grnData.put("module", "purchase");
                grnData.put("reportType", reportType);
                grnData.put("startDate", String.valueOf(fromDate));
                grnData.put("endDate", String.valueOf(toDate));
                grnData.put("reportData", grnDataListByProduct);
                grnData.put("column", column);
                grnData.put("pagination", pagination);
                grnData.put("summary", summary);

                // Create and return the structured ApiResponseStructure
                return new ApiResponseStructure<>("Success", 200, "Data retrieved.", grnData);
            case "annual":
                // Add dynamic conditions
                if (purchaseRequest.getConditions() != null) {
                    for (PurchaseRequest.Condition condition : purchaseRequest.getConditions()) {
                        switch (condition.getOperator()) {
                            case "equals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(condition.getField()), condition.getValue()));
                                break;
                            case "greaterThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThan":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "greaterThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThanOrEquals":
                                spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            default:
                                createLogger.createLogger("error", path, "POST", "", "");
                                throw new IllegalArgumentException("Operator " + condition.getOperator() + " is not supported.");
                        }
                    }
                }

                // Fetch the data with pagination for GRN items
                pageable = PageRequest.of(purchaseRequest.getPage() != null ? purchaseRequest.getPage() : 0, // Page number is zero-based
                        purchaseRequest.getSize() != null ? purchaseRequest.getSize() : 20);

                // Fetch all GRNItems based on the specification
                grnItemPage = grnItemRepository.findAll(spec, pageable);

                // Group GRN items by product_id
                groupedGRNDataByProduct = new HashMap<>();

                // Iterate through each GRNItem and accumulate quantities and total prices
                grnItemPage.getContent().forEach(item -> {
                    Long productId = item.getProduct_id(); // Get product ID
                    String productName = productRepository.findProductNameById(productId, tenantName); // Fetch product name
                    Long categoryId = productRepository.findCategoryIdByProductId(productId, tenantName); // Fetch category ID
                    Long brandId = productRepository.findBrandIdByProductId(productId, tenantName); // Fetch brand ID
                    String categoryName = categoryRepository.findCategoryNameById(categoryId, tenantName); // Fetch category name
                    String brandName = brandRepository.findBrandNameById(brandId, tenantName); // Fetch brand name

                    // Create a new entry for the product if it doesn't exist
                    groupedGRNDataByProduct.computeIfAbsent(productId, id -> {
                        Map<String, Object> data = new LinkedHashMap<>();
                        data.put("product_id", productId);
                        data.put("product_name", productName);
                        data.put("category_id", categoryId);
                        data.put("category_name", categoryName);
                        data.put("brand_id", brandId);
                        data.put("brand_name", brandName);
                        data.put("quantity", 0);
                        data.put("total_price", 0.00);
                        return data;
                    });

                    // Get the current data for the product
                    Map<String, Object> data = groupedGRNDataByProduct.get(productId);
                    data.put("quantity", (Integer) data.get("quantity") + item.getQuantity());
                    data.put("total_price", MoneyUtils.truncateToTwoDecimals((Double) data.get("total_price") + item.getTotal_price())); // Sum total price
                });

                // Prepare reportData list from the grouped data
                grnDataListByProduct = new ArrayList<>(groupedGRNDataByProduct.values());

                // Prepare column details
                column = new LinkedHashMap<>();
                column.put("product_id", "PRODUCT ID");
                column.put("product_name", "PRODUCT NAME");
                column.put("category_id", "CATEGORY ID");
                column.put("category_name", "CATEGORY NAME");
                column.put("brand_id", "BRAND ID");
                column.put("brand_name", "BRAND NAME");
                column.put("quantity", "QUANTITY");
                column.put("total_price", "TOTAL PRICE");

                // Prepare pagination details
                pagination = new LinkedHashMap<>();
                pagination.put("currentPage", grnItemPage.getNumber() + 1); // Page number is 0-based
                pagination.put("totalPages", grnItemPage.getTotalPages());
                pagination.put("pageSize", pageable.getPageSize());
                pagination.put("totalRecords", groupedGRNDataByProduct.size());

                // Calculate summary details
                totalRevenue = grnDataListByProduct.stream().mapToDouble(data -> (Double) data.get("total_price")).sum();

                totalItemsSold = grnDataListByProduct.stream().mapToInt(data -> (Integer) data.get("quantity")).sum();

                // Find the top purchased product based on total quantity
                productSalesMap = new HashMap<>();
                grnDataListByProduct.forEach(data -> {
                    Long productId = (Long) data.get("product_id");
                    Integer quantity = (Integer) data.get("quantity");
                    productSalesMap.put(productId, productSalesMap.getOrDefault(productId, 0) + quantity);
                });

                topPurchasedProductId = productSalesMap.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);

                topPurchasedProductName = null;
                if (topPurchasedProductId != null) {
                    topPurchasedProductName = productRepository.findProductNameById(topPurchasedProductId, tenantName); // Fetch the top product name
                }

                // Prepare summary details
                summary = new LinkedHashMap<>();
                summary.put("totalRevenue", MoneyUtils.truncateToTwoDecimals(totalRevenue));
                summary.put("totalItemsSold", totalItemsSold);
                summary.put("topPurchasedProduct", topPurchasedProductName);

                // Prepare response data
                grnData = new LinkedHashMap<>();
                grnData.put("module", "purchase");
                grnData.put("reportType", reportType);
                grnData.put("startDate", String.valueOf(fromDate));
                grnData.put("endDate", String.valueOf(toDate));
                grnData.put("reportData", grnDataListByProduct);
                grnData.put("column", column);
                grnData.put("pagination", pagination);
                grnData.put("summary", summary);

                // Create and return the structured ApiResponseStructure
                return new ApiResponseStructure<>("Success", 200, "Data retrieved.", grnData);
            case "purchaseReturns":
                // Create a specification for the query
                Specification<PurchaseReturnItem> specs = Specification.where(null);

                // Add tenant name filtering
                specs = specs.and((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("tenant"), tenantName));

                // Add date range filtering
                if (purchaseRequest.getStartDate() != null && purchaseRequest.getEndDate() != null) {
                    specs = specs.and((root, query, criteriaBuilder) -> criteriaBuilder.between(root.get("created_at"), fromDateTime, toDateTime));
                }

                // Add dynamic conditions
                if (purchaseRequest.getConditions() != null) {
                    for (PurchaseRequest.Condition condition : purchaseRequest.getConditions()) {
                        switch (condition.getOperator()) {
                            case "equals":
                                specs = specs.and((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(condition.getField()), condition.getValue()));
                                break;
                            case "greaterThan":
                                specs = specs.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThan":
                                specs = specs.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThan(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "greaterThanOrEquals":
                                specs = specs.and((root, query, criteriaBuilder) -> criteriaBuilder.greaterThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            case "lessThanOrEquals":
                                specs = specs.and((root, query, criteriaBuilder) -> criteriaBuilder.lessThanOrEqualTo(root.get(condition.getField()), (Comparable) condition.getValue()));
                                break;
                            default:
                                createLogger.createLogger("error", path, "POST", "", "");
                                throw new IllegalArgumentException("Operator " + condition.getOperator() + " is not supported.");
                        }
                    }
                }

                // Fetch all PurchaseReturnItems based on the specification
                pageable = PageRequest.of(purchaseRequest.getPage() != null ? purchaseRequest.getPage() : 0, // Page number is zero-based
                        purchaseRequest.getSize() != null ? purchaseRequest.getSize() : 20);

                Page<PurchaseReturnItem> purchaseReturnItemsPage = purchaseReturnItemRepository.findAll(specs, pageable);

                // Group Purchase Return Items by product_id
                Map<String, Map<String, Object>> groupedReturnData = new HashMap<>();
                Map<String, Integer> quantityMap = new HashMap<>();

                purchaseReturnItemsPage.getContent().forEach(item -> {
                    String productId = String.valueOf(item.getProduct_id()); // Get product ID
                    String productName = productRepository.findProductNameById(Long.valueOf(productId), tenantName); // Fetch product name
                    Long categoryId = productRepository.findCategoryIdByProductId(Long.valueOf(productId), tenantName); // Fetch category ID
                    Long brandId = productRepository.findBrandIdByProductId(Long.valueOf(productId), tenantName); // Fetch brand ID
                    String categoryName = categoryRepository.findCategoryNameById(categoryId, tenantName); // Fetch category name
                    String brandName = brandRepository.findBrandNameById(brandId, tenantName);

                    // Create a new entry for the product if it doesn't exist
                    groupedReturnData.computeIfAbsent(productId, id -> {
                        Map<String, Object> data = new LinkedHashMap<>();
                        data.put("product_id", productId);
                        data.put("product_name", productName); // Fetch product name
                        data.put("category_id", categoryId); // Fetch category ID
                        data.put("category_name", categoryName); // Fetch category name
                        data.put("brand_id", brandId); // Fetch brand ID
                        data.put("brand_name", brandName); // Fetch brand name
                        data.put("quantity", 0);
                        data.put("total_price", 0.00);
                        return data;
                    });

                    // Update totals
                    Map<String, Object> data = groupedReturnData.get(productId);
                    int currentQuantity = item.getQuantity();
                    data.put("quantity", (Integer) data.get("quantity") + item.getQuantity());

                    // Update the quantity map for most returned product
                    quantityMap.put(productId, quantityMap.getOrDefault(productId, 0) + currentQuantity);

                    // Fetch the original price of the product to calculate total_price
                    Double itemPrice = productRepository.findProductPriceById(productId, tenantName); // Fetch product price based on ID
                    if (itemPrice != null) {
                        data.put("total_price", MoneyUtils.truncateToTwoDecimals(((Double) data.get("total_price")) + (itemPrice * (Double.valueOf(item.getQuantity())))));
                    }
                });

                // Prepare reportData list from the grouped data
                List<Map<String, Object>> returnDataList = new ArrayList<>(groupedReturnData.values());

                // Prepare column details
                Map<String, Object> returnColumn = new LinkedHashMap<>();
                returnColumn.put("product_id", "PRODUCT ID");
                returnColumn.put("product_name", "PRODUCT NAME");
                returnColumn.put("category_id", "CATEGORY ID");
                returnColumn.put("category_name", "CATEGORY NAME");
                returnColumn.put("brand_id", "BRAND ID");
                returnColumn.put("brand_name", "BRAND NAME");
                returnColumn.put("quantity", "QUANTITY");
                returnColumn.put("total_price", "TOTAL PRICE");

                // Calculate summary details
                double totalReturnRevenue = returnDataList.stream().mapToDouble(data -> (Double) data.get("total_price")).sum();

                // Calculate total quantity returned and most returned product
                int totalQuantityReturned = quantityMap.values().stream().mapToInt(Integer::intValue).sum();
                String mostReturnedProduct = quantityMap.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);
                String mostReturnedProductName = mostReturnedProduct != null ? productRepository.findProductNameById(Long.valueOf(mostReturnedProduct), tenantName) : null;

                // Prepare summary details
                Map<String, Object> returnSummary = new LinkedHashMap<>();
                returnSummary.put("totalReturnAmount", MoneyUtils.truncateToTwoDecimals(totalReturnRevenue));
                returnSummary.put("totalQuantityReturned", totalQuantityReturned);
                returnSummary.put("mostReturnedProduct", mostReturnedProductName);

                // Prepare response data
                Map<String, Object> returnData = new LinkedHashMap<>();
                returnData.put("module", "purchase");
                returnData.put("reportType", reportType);
                returnData.put("reportData", returnDataList);
                returnData.put("column", returnColumn);
                returnData.put("summary", returnSummary);

                // Create and return the structured ApiResponseStructure
                return new ApiResponseStructure<>("Success", 200, "Purchase return data retrieved.", returnData);
            default:
                createLogger.createLogger("error", path, "POST", "Invalid report type provided.", "");
                return new ApiResponseStructure<>("Error", 400, "Invalid report type provided.", new HashMap<>());
        }
    }

}