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

package com.nebula.erp.reports.service;

import com.nebula.erp.reports.model.product.Tax;
import com.nebula.erp.reports.model.sales.SalesItem;
import com.nebula.erp.reports.repository.product.BrandRepository;
import com.nebula.erp.reports.repository.product.CategoryRepository;
import com.nebula.erp.reports.repository.product.TaxRepository;
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.SalesRequest;
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.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class TaxService {

    @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 TaxRepository taxRepository;

    @Autowired
    private BrandRepository brandRepository;

    @Autowired
    private JwtRequestUtils jwtRequestUtils;

    @Autowired
    private HttpServletRequest httpServletRequest;

    @Autowired
    private CreateLogger createLogger;

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

    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);

            // Initialize totals
            BigDecimal totalTaxesCollected = BigDecimal.ZERO;
            BigDecimal gstCollected = BigDecimal.ZERO;

            // Fetch all sales items based on date range and tenant name
            List<SalesItem> salesItems = salesItemRepository.findAllSalesItemsByDateRange(fromDateTime, toDateTime,
                    tenantName);

            for (SalesItem item : salesItems) {
                if (item.getTax_id() != null) {
                    BigDecimal amount = BigDecimal.valueOf(item.getTotal_price());
                    // Fetch tax rate using tax ID and tenant name
                    BigDecimal taxRate = taxRepository.findTaxRateById(item.getTax_id(), tenantName);
                    if (taxRate != null) {
                        // Calculate tax amount
                        BigDecimal taxAmount = amount.multiply(taxRate).divide(BigDecimal.valueOf(100));
                        totalTaxesCollected = totalTaxesCollected.add(taxAmount);

                        // Check if the tax is GST
                        if ("GST".equalsIgnoreCase(taxRepository.findTaxTypeById(item.getTax_id(), tenantName))) {
                            gstCollected = gstCollected.add(taxAmount);
                        }
                    }
                }
            }

            // Calculate total sales amount
            BigDecimal totalSalesAmount = salesItems.stream().map(item -> BigDecimal.valueOf(item.getTotal_price()))
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            // Prepare response data
            Map<String, Object> salesData = new LinkedHashMap<>();
            salesData.put("total_taxes_collected", MoneyUtils.truncateToTwoDecimals(totalTaxesCollected.doubleValue()));
            salesData.put("gst_collected", MoneyUtils.truncateToTwoDecimals(gstCollected.doubleValue()));
            salesData.put("total_sales_with_tax",
                    MoneyUtils.truncateToTwoDecimals(totalSalesAmount.add(totalTaxesCollected).doubleValue())); // Total
                                                                                                                // sales
                                                                                                                // including
                                                                                                                // taxes

            // Create and return the structured ApiResponseStructure
            return new ApiResponseStructure<>("Success", 200, "Data retrieved.", salesData);
        }
        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>> getTaxReport(SalesRequest salesRequest, 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 (salesRequest.getStartDate() == null || salesRequest.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<>());
        }

        // Convert LocalDate to LocalDateTime
        LocalDateTime fromDateTime = salesRequest.getStartDate().atStartOfDay();
        LocalDateTime toDateTime = salesRequest.getEndDate().atTime(23, 59, 59);

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

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

        // Add date range filtering
        spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.between(root.get("created_at"), fromDateTime,
                toDateTime));

        // Switch cases to handle various report type
        switch (reportType) {
            case "gstVatSummary":
                // Add dynamic conditions
                if (salesRequest.getConditions() != null) {
                    for (SalesRequest.Condition condition : salesRequest.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",
                                        "Operator " + condition.getOperator() + " is not supported.", "");
                                throw new IllegalArgumentException(
                                        "Operator " + condition.getOperator() + " is not supported.");
                        }
                    }
                }

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

                // Prepare response data
                List<Map<String, Object>> reportData = new ArrayList<>();
                BigDecimal totalGstCollected = BigDecimal.ZERO;

                // Fetch all sales items based on tenant name and date range
                Page<SalesItem> salesItems = salesItemRepository.findAll(spec, pageable);

                for (SalesItem item : salesItems) {
                    if (item.getTax_id() != null) {
                        // Fetch the Tax entity using the tax ID
                        Tax tax = taxRepository.findById(item.getTax_id()).orElse(null);
                        if (tax != null) {
                            BigDecimal gstAmount = BigDecimal.valueOf(item.getTotal_price()).multiply(tax.getRate())
                                    .divide(BigDecimal.valueOf(100));

                            totalGstCollected = totalGstCollected.add(gstAmount);

                            // Calculate CGST/SGST if split
                            boolean isSplit = Boolean.TRUE.equals(tax.getIsSplit());
                            BigDecimal cgstAmount = isSplit && tax.getCgstRate() != null
                                    ? BigDecimal.valueOf(item.getTotal_price()).multiply(tax.getCgstRate())
                                            .divide(BigDecimal.valueOf(100))
                                    : BigDecimal.ZERO;
                            BigDecimal sgstAmount = isSplit && tax.getSgstRate() != null
                                    ? BigDecimal.valueOf(item.getTotal_price()).multiply(tax.getSgstRate())
                                            .divide(BigDecimal.valueOf(100))
                                    : BigDecimal.ZERO;

                            // Create report entry
                            Map<String, Object> reportEntry = new LinkedHashMap<>();
                            reportEntry.put("sale_id", item.getSales().getId());
                            reportEntry.put("tax_type", tax.getType());
                            reportEntry.put("tax_rate", tax.getRate());
                            reportEntry.put("is_split", isSplit);
                            reportEntry.put("tax_collected", MoneyUtils.truncateToTwoDecimals(gstAmount.doubleValue()));
                            if (isSplit) {
                                reportEntry.put("cgst_rate", tax.getCgstRate());
                                reportEntry.put("cgst_collected",
                                        MoneyUtils.truncateToTwoDecimals(cgstAmount.doubleValue()));
                                reportEntry.put("sgst_rate", tax.getSgstRate());
                                reportEntry.put("sgst_collected",
                                        MoneyUtils.truncateToTwoDecimals(sgstAmount.doubleValue()));
                            }
                            reportEntry.put("sale_date", String.valueOf(item.getCreated_at()));

                            reportData.add(reportEntry);
                        }
                    }
                }

                // Prepare column details
                Map<String, Object> column = new LinkedHashMap<>();
                column.put("sale_id", "SALES ID");
                column.put("tax_type", "TAX TYPE");
                column.put("tax_rate", "TAX RATE");
                column.put("is_split", "GST SPLIT");
                column.put("tax_collected", "TAX COLLECTED");
                column.put("cgst_rate", "CGST RATE");
                column.put("cgst_collected", "CGST COLLECTED");
                column.put("sgst_rate", "SGST RATE");
                column.put("sgst_collected", "SGST COLLECTED");
                column.put("sale_date", "SALE DATE");

                // Prepare pagination details
                Map<String, Object> pagination = new LinkedHashMap<>();
                pagination.put("currentPage", salesItems.getNumber() + 1); // Page number is 0-based
                pagination.put("totalPages", salesItems.getTotalPages());
                pagination.put("pageSize", pageable.getPageSize());
                pagination.put("totalRecords", salesItems.getTotalElements()); // Total records from the Page object

                // Prepare summary details
                Map<String, Object> summary = new LinkedHashMap<>();
                summary.put("totalTaxesCollected", MoneyUtils.truncateToTwoDecimals(totalGstCollected.doubleValue())); // Adjust
                                                                                                                       // this
                                                                                                                       // based
                                                                                                                       // on
                                                                                                                       // your
                                                                                                                       // logic
                                                                                                                       // to
                                                                                                                       // include
                                                                                                                       // total
                                                                                                                       // taxes
                summary.put("gstCollected", MoneyUtils.truncateToTwoDecimals(totalGstCollected.doubleValue())); // This
                                                                                                                // represents
                                                                                                                // GST
                                                                                                                // collected
                summary.put("vatCollected", BigDecimal.ZERO); // Assuming you want to set this to zero or calculate
                                                              // separately

                // Prepare the final response data
                Map<String, Object> gstResponseData = new LinkedHashMap<>();
                gstResponseData.put("module", "tax");
                gstResponseData.put("reportType", "gstVatSummary");
                gstResponseData.put("startDate", String.valueOf(salesRequest.getStartDate()));
                gstResponseData.put("endDate", String.valueOf(salesRequest.getEndDate()));
                gstResponseData.put("reportData", reportData);
                gstResponseData.put("column", column);
                gstResponseData.put("pagination", pagination);
                gstResponseData.put("summary", summary);

                // Create and return the structured ApiResponseStructure
                return new ApiResponseStructure<>("Success", 200, "Data retrieved.", gstResponseData);

            case "taxByProductCategory":
                // Add dynamic conditions
                if (salesRequest.getConditions() != null) {
                    for (SalesRequest.Condition condition : salesRequest.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",
                                        "Operator " + condition.getOperator() + " is not supported.", "");
                                throw new IllegalArgumentException(
                                        "Operator " + condition.getOperator() + " is not supported.");
                        }
                    }
                }

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

                // Create a map to store tax collected by product and category
                Map<String, BigDecimal> taxByProductCategoryMap = new HashMap<>();
                List<Map<String, Object>> taxDataList = new ArrayList<>();

                // Initialize summary variables
                BigDecimal totalTaxesCollected = BigDecimal.ZERO;
                BigDecimal gstCollected = BigDecimal.ZERO;
                BigDecimal vatCollected = BigDecimal.ZERO;

                // Fetch all sales items based on tenant name and date range
                salesItems = salesItemRepository.findAll(spec, pageable);

                // Map to store Tax entity per product for split info
                Map<String, Tax> taxEntityByProduct = new HashMap<>();

                for (SalesItem item : salesItems) {
                    if (item.getTax_id() != null) {
                        // Fetch full Tax entity for split info
                        Tax tax = taxRepository.findById(item.getTax_id()).orElse(null);
                        if (tax != null) {
                            BigDecimal taxRate = tax.getRate();
                            // Calculate tax amount
                            BigDecimal taxAmount = BigDecimal.valueOf(item.getTotal_price()).multiply(taxRate)
                                    .divide(BigDecimal.valueOf(100));

                            // Collect tax by product and category
                            if (item.getProduct_id() != null && !item.getProduct_id().trim().isEmpty()) {
                                taxByProductCategoryMap.merge(item.getProduct_id().trim(), taxAmount, BigDecimal::add);
                                // Store tax entity for later use
                                taxEntityByProduct.putIfAbsent(item.getProduct_id().trim(), tax);
                            }

                            // Add to total taxes collected
                            totalTaxesCollected = totalTaxesCollected.add(taxAmount);

                            // Check if tax type is GST or VAT
                            if ("GST".equalsIgnoreCase(tax.getType())) {
                                gstCollected = gstCollected.add(taxAmount);
                            } else if ("VAT".equalsIgnoreCase(tax.getType())) {
                                vatCollected = vatCollected.add(taxAmount);
                            }
                        }
                    }
                }

                // Prepare data list for response
                for (Map.Entry<String, BigDecimal> entry : taxByProductCategoryMap.entrySet()) {

                    Map<String, Object> taxData = new LinkedHashMap<>();
                    String rawProductId = entry.getKey();

                    Long productId = null;

                    try {
                        productId = Long.valueOf(rawProductId);
                    } catch (NumberFormatException ex) {
                        // Skip UUID or invalid product ids safely
                        continue;
                    }

                    String productName = productRepository.findProductNameById(productId, tenantName);
                    Long categoryId = productRepository.findCategoryIdByProductId(productId, tenantName);
                    Long brandId = productRepository.findBrandIdByProductId(productId, tenantName);

                    String categoryName = categoryRepository.findCategoryNameById(categoryId, tenantName);
                    String brandName = brandRepository.findBrandNameById(brandId, tenantName);

                    taxData.put("product_id", productId);
                    taxData.put("product_name", productName);
                    taxData.put("category_id", categoryId);
                    taxData.put("category_name", categoryName);
                    taxData.put("brand_id", brandId);
                    taxData.put("brand_name", brandName);
                    taxData.put("total_tax_collected",
                            MoneyUtils.truncateToTwoDecimals(entry.getValue().doubleValue()));

                    // Add CGST/SGST split info if available
                    Tax productTax = taxEntityByProduct.get(rawProductId);
                    if (productTax != null) {
                        taxData.put("tax_rate", productTax.getRate());
                        if (Boolean.TRUE.equals(productTax.getIsSplit())) {
                            BigDecimal totalTax = entry.getValue();
                            BigDecimal cgst = totalTax.divide(BigDecimal.valueOf(2));
                            BigDecimal sgst = totalTax.divide(BigDecimal.valueOf(2));
                            taxData.put("is_split", true);
                            taxData.put("cgst_rate", productTax.getCgstRate());
                            taxData.put("cgst_collected", MoneyUtils.truncateToTwoDecimals(cgst.doubleValue()));
                            taxData.put("sgst_rate", productTax.getSgstRate());
                            taxData.put("sgst_collected", MoneyUtils.truncateToTwoDecimals(sgst.doubleValue()));
                        } else {
                            taxData.put("is_split", false);
                        }
                    } else {
                        taxData.put("tax_rate", null);
                        taxData.put("is_split", false);
                    }

                    taxDataList.add(taxData);
                }

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

                // 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_tax_collected", "TOTAL TAX COLLECTED");
                column.put("tax_rate", "TAX RATE");
                column.put("is_split", "GST SPLIT");
                column.put("cgst_rate", "CGST RATE");
                column.put("cgst_collected", "CGST COLLECTED");
                column.put("sgst_rate", "SGST RATE");
                column.put("sgst_collected", "SGST COLLECTED");

                // Prepare summary details
                summary = new LinkedHashMap<>();
                summary.put("totalTaxesCollected", MoneyUtils.truncateToTwoDecimals(totalTaxesCollected.doubleValue()));
                summary.put("gstCollected", MoneyUtils.truncateToTwoDecimals(gstCollected.doubleValue()));
                summary.put("vatCollected", MoneyUtils.truncateToTwoDecimals(vatCollected.doubleValue()));

                // Prepare response data
                Map<String, Object> taxResponseData = new LinkedHashMap<>();
                taxResponseData.put("module", "tax");
                taxResponseData.put("reportType", reportType);
                taxResponseData.put("startDate", String.valueOf(salesRequest.getStartDate()));
                taxResponseData.put("endDate", String.valueOf(salesRequest.getEndDate()));
                taxResponseData.put("reportData", taxDataList);
                taxResponseData.put("column", column);
                taxResponseData.put("pagination", pagination);
                taxResponseData.put("summary", summary);

                // Create and return the structured ApiResponseStructure
                return new ApiResponseStructure<>("Success", 200, "Data retrieved.", taxResponseData);

            case "byHealthcareCategory":
                // Add dynamic conditions
                if (salesRequest.getConditions() != null) {
                    for (SalesRequest.Condition condition : salesRequest.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",
                                        "Operator " + condition.getOperator() + " is not supported.", "");
                                throw new IllegalArgumentException(
                                        "Operator " + condition.getOperator() + " is not supported.");
                        }
                    }
                }

                // Filter only service, package, bed types
                spec = spec.and((root, query, criteriaBuilder) -> root.get("type").in("service", "package", "bed"));

                // Pagination
                pageable = PageRequest.of(
                        salesRequest.getPage() != null ? salesRequest.getPage() : 0,
                        salesRequest.getSize() != null ? salesRequest.getSize() : 20);

                // Fetch items
                Page<SalesItem> healthcareItems = salesItemRepository.findAll(spec, pageable);

                // Group by type + product_name
                Map<String, Map<String, Object>> healthcareGroupMap = new LinkedHashMap<>();
                BigDecimal totalHealthcareTax = BigDecimal.ZERO;
                BigDecimal healthcareGstCollected = BigDecimal.ZERO;

                for (SalesItem item : healthcareItems) {
                    String itemType = item.getType() != null ? item.getType().toLowerCase() : "unknown";
                    String rawName = item.getProduct_name();
                    // Skip items where product_name is null or looks like a UUID or pure number
                    boolean isUuidOrNumeric = rawName == null || rawName.isEmpty()
                            || rawName.matches("[0-9a-fA-F\\-]{36}")  // UUID pattern
                            || rawName.matches("\\d+");               // Pure numeric ID
                    if (isUuidOrNumeric) continue;

                    String productName = rawName;
                    String groupKey = itemType + "_" + productName;

                    Tax tax = item.getTax_id() != null
                            ? taxRepository.findById(item.getTax_id()).orElse(null)
                            : null;

                    BigDecimal taxAmount = BigDecimal.ZERO;
                    if (tax != null) {
                        taxAmount = BigDecimal.valueOf(item.getTotal_price())
                                .multiply(tax.getRate())
                                .divide(BigDecimal.valueOf(100));
                    }

                    totalHealthcareTax = totalHealthcareTax.add(taxAmount);
                    if (tax != null && "GST".equalsIgnoreCase(tax.getType())) {
                        healthcareGstCollected = healthcareGstCollected.add(taxAmount);
                    }

                    if (!healthcareGroupMap.containsKey(groupKey)) {
                        Map<String, Object> entry = new LinkedHashMap<>();
                        entry.put("type", itemType);
                        entry.put("item_name", productName);
                        entry.put("tax_type", tax != null ? tax.getType() : "-");
                        entry.put("tax_rate", tax != null ? tax.getRate() : null);
                        entry.put("is_split", tax != null && Boolean.TRUE.equals(tax.getIsSplit()));
                        entry.put("cgst_rate",
                                tax != null && Boolean.TRUE.equals(tax.getIsSplit()) ? tax.getCgstRate() : null);
                        entry.put("sgst_rate",
                                tax != null && Boolean.TRUE.equals(tax.getIsSplit()) ? tax.getSgstRate() : null);
                        entry.put("total_quantity", item.getQuantity());
                        entry.put("tax_collected", taxAmount);
                        entry.put("cgst_collected", tax != null && Boolean.TRUE.equals(tax.getIsSplit())
                                ? taxAmount.divide(BigDecimal.valueOf(2))
                                : BigDecimal.ZERO);
                        entry.put("sgst_collected", tax != null && Boolean.TRUE.equals(tax.getIsSplit())
                                ? taxAmount.divide(BigDecimal.valueOf(2))
                                : BigDecimal.ZERO);
                        healthcareGroupMap.put(groupKey, entry);
                    } else {
                        Map<String, Object> existing = healthcareGroupMap.get(groupKey);
                        BigDecimal existingTax = (BigDecimal) existing.get("tax_collected");
                        existing.put("tax_collected", existingTax.add(taxAmount));
                        existing.put("total_quantity",
                                (Integer) existing.get("total_quantity") + item.getQuantity());
                        if (tax != null && Boolean.TRUE.equals(tax.getIsSplit())) {
                            BigDecimal existingCgst = (BigDecimal) existing.get("cgst_collected");
                            BigDecimal existingSgst = (BigDecimal) existing.get("sgst_collected");
                            existing.put("cgst_collected", existingCgst.add(taxAmount.divide(BigDecimal.valueOf(2))));
                            existing.put("sgst_collected", existingSgst.add(taxAmount.divide(BigDecimal.valueOf(2))));
                        }
                    }
                }

                // Convert to list with formatted values
                List<Map<String, Object>> healthcareReportData = new ArrayList<>();
                for (Map<String, Object> entry : healthcareGroupMap.values()) {
                    Map<String, Object> row = new LinkedHashMap<>();
                    row.put("type", entry.get("type"));
                    row.put("item_name", entry.get("item_name"));
                    row.put("total_quantity", entry.get("total_quantity"));
                    row.put("tax_type", entry.get("tax_type"));
                    row.put("tax_rate", entry.get("tax_rate"));
                    row.put("is_split", entry.get("is_split"));
                    row.put("tax_collected",
                            MoneyUtils.truncateToTwoDecimals(((BigDecimal) entry.get("tax_collected")).doubleValue()));
                    if (Boolean.TRUE.equals(entry.get("is_split"))) {
                        row.put("cgst_rate", entry.get("cgst_rate"));
                        row.put("cgst_collected",
                                MoneyUtils.truncateToTwoDecimals(
                                        ((BigDecimal) entry.get("cgst_collected")).doubleValue()));
                        row.put("sgst_rate", entry.get("sgst_rate"));
                        row.put("sgst_collected",
                                MoneyUtils.truncateToTwoDecimals(
                                        ((BigDecimal) entry.get("sgst_collected")).doubleValue()));
                    }
                    healthcareReportData.add(row);
                }

                // Column map
                Map<String, Object> healthcareColumn = new LinkedHashMap<>();
                healthcareColumn.put("type", "TYPE");
                healthcareColumn.put("item_name", "ITEM NAME");
                healthcareColumn.put("total_quantity", "TOTAL QUANTITY");
                healthcareColumn.put("tax_type", "TAX TYPE");
                healthcareColumn.put("tax_rate", "TAX RATE");
                healthcareColumn.put("is_split", "GST SPLIT");
                healthcareColumn.put("tax_collected", "TAX COLLECTED");
                healthcareColumn.put("cgst_rate", "CGST RATE");
                healthcareColumn.put("cgst_collected", "CGST COLLECTED");
                healthcareColumn.put("sgst_rate", "SGST RATE");
                healthcareColumn.put("sgst_collected", "SGST COLLECTED");

                // Pagination
                Map<String, Object> healthcarePagination = new LinkedHashMap<>();
                healthcarePagination.put("currentPage", healthcareItems.getNumber() + 1);
                healthcarePagination.put("totalPages", healthcareItems.getTotalPages());
                healthcarePagination.put("pageSize", pageable.getPageSize());
                healthcarePagination.put("totalRecords", healthcareItems.getTotalElements());

                // Summary
                Map<String, Object> healthcareSummary = new LinkedHashMap<>();
                healthcareSummary.put("totalTaxesCollected",
                        MoneyUtils.truncateToTwoDecimals(totalHealthcareTax.doubleValue()));
                healthcareSummary.put("gstCollected",
                        MoneyUtils.truncateToTwoDecimals(healthcareGstCollected.doubleValue()));
                healthcareSummary.put("vatCollected", 0);

                // Response
                Map<String, Object> healthcareResponseData = new LinkedHashMap<>();
                healthcareResponseData.put("module", "tax");
                healthcareResponseData.put("reportType", "byHealthcareCategory");
                healthcareResponseData.put("startDate", String.valueOf(salesRequest.getStartDate()));
                healthcareResponseData.put("endDate", String.valueOf(salesRequest.getEndDate()));
                healthcareResponseData.put("reportData", healthcareReportData);
                healthcareResponseData.put("column", healthcareColumn);
                healthcareResponseData.put("pagination", healthcarePagination);
                healthcareResponseData.put("summary", healthcareSummary);

                return new ApiResponseStructure<>("Success", 200, "Data retrieved.", healthcareResponseData);

            default:
                createLogger.createLogger("error", path, "POST", "Invalid report type provided.", "");
                return new ApiResponseStructure<>("Error", 400, "Invalid report type provided.", new HashMap<>());
        }
    }

}