Subversion Repositories SmartDukaan

Rev

Blame | Last modification | View Log | RSS feed

package com.spice.profitmandi.web.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.spice.profitmandi.dao.entity.catalog.Item;
import com.spice.profitmandi.dao.entity.dtr.WebOffer;
import com.spice.profitmandi.dao.entity.dtr.WebOfferProduct;
import com.spice.profitmandi.dao.repository.catalog.ItemRepository;
import com.spice.profitmandi.dao.repository.dtr.WebOfferProductRepository;
import com.spice.profitmandi.dao.repository.dtr.WebOfferRepository;
import com.spice.profitmandi.web.model.EmiOfferImportDTO;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Imports EMI scraper JSON (one JSON per scrape run) and creates one
 * dtr.web_offer per (product × bank), with a dtr.web_offer_product row linking
 * the catalog_id. Plan details are summarised into detailedText.
 * <p>
 * SKU resolution: catalog.item.brand_identifier -> catalog.item.catalog_item_id
 * which is the WebOfferProduct.entityId.
 */
@Service
public class EmiOfferImportService {

    private static final Logger LOGGER = LogManager.getLogger(EmiOfferImportService.class);

    @Autowired
    private ItemRepository itemRepository;

    @Autowired
    private WebOfferRepository webOfferRepository;

    @Autowired
    private WebOfferProductRepository webOfferProductRepository;

    public ImportResult importFromJson(InputStream in, LocalDateTime startDate, LocalDateTime endDate, boolean dryRun)
            throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        EmiOfferImportDTO dto = mapper.readValue(in, EmiOfferImportDTO.class);

        ImportResult result = new ImportResult();
        result.dryRun = dryRun;
        result.generatedAt = dto.getGeneratedAt();

        if (dto.getProducts() == null || dto.getProducts().isEmpty()) {
            return result;
        }

        List<String> skus = dto.getProducts().stream()
                .map(EmiOfferImportDTO.Product::getSku)
                .filter(s -> s != null && !s.isEmpty())
                .distinct()
                .collect(Collectors.toList());

        Map<String, Integer> skuToCatalogId = resolveSkus(skus, result);

        for (EmiOfferImportDTO.Product product : dto.getProducts()) {
            Integer catalogId = skuToCatalogId.get(product.getSku());
            if (catalogId == null) {
                continue; // already recorded in missingSkus
            }
            if (product.getCardTypes() == null) continue;

            for (EmiOfferImportDTO.CardType cardType : product.getCardTypes()) {
                if (cardType.getBanks() == null) continue;
                for (EmiOfferImportDTO.Bank bank : cardType.getBanks()) {
                    if (bank.getPlans() == null || bank.getPlans().isEmpty()) {
                        result.banksSkippedNoPlans++;
                        continue;
                    }
                    createOffer(product, cardType, bank, catalogId, startDate, endDate, dryRun, result);
                }
            }
        }

        return result;
    }

    private Map<String, Integer> resolveSkus(List<String> skus, ImportResult result) {
        Map<String, Integer> out = new HashMap<>();
        if (skus.isEmpty()) return out;

        LOGGER.info("EmiImport: resolving {} sku(s): {}", skus.size(), skus);
        List<Item> items = itemRepository.selectAllByBrandIdentifiers(skus);
        LOGGER.info("EmiImport: itemRepository returned {} row(s) for {} sku(s)", items.size(), skus.size());

        Set<String> matched = new HashSet<>();
        for (Item item : items) {
            String sku = item.getBrandIdentifier();
            LOGGER.info("EmiImport:   matched item id={} brandIdentifier='{}' catalogItemId={}",
                    item.getId(), sku, item.getCatalogItemId());
            if (sku == null) continue;
            matched.add(sku);
            // keep first occurrence; catalog_item_id should be identical across colors of same catalog
            out.putIfAbsent(sku, item.getCatalogItemId());
        }
        for (String sku : skus) {
            if (!matched.contains(sku)) {
                LOGGER.warn("EmiImport: NO match for sku '{}' (len={})", sku, sku == null ? -1 : sku.length());
                result.missingSkus.add(sku);
            }
        }
        return out;
    }

    private void createOffer(EmiOfferImportDTO.Product product, EmiOfferImportDTO.CardType cardType,
                             EmiOfferImportDTO.Bank bank, int catalogId, LocalDateTime startDate, LocalDateTime endDate,
                             boolean dryRun, ImportResult result) {

        String title = bank.getBankName();
        String smallText = inferOfferTypeSummary(bank.getPlans());
        String detailedText = buildDetailedText(product, bank);

        OfferPreview preview = new OfferPreview();
        preview.sku = product.getSku();
        preview.catalogId = catalogId;
        preview.title = title;
        preview.smallText = smallText;
        preview.detailedText = detailedText;
        preview.planCount = bank.getPlans().size();
        result.previews.add(preview);

        if (dryRun) {
            result.offersWouldCreate++;
            return;
        }

        WebOffer offer = new WebOffer();
        offer.setTitle(title);
        offer.setSmallText(smallText);
        offer.setDetailedText(detailedText);
        offer.setStartDate(startDate);
        offer.setEndDate(endDate);
        offer.setActive(true);
        offer.setCreatedDate(LocalDateTime.now());
        webOfferRepository.persist(offer);

        WebOfferProduct wop = new WebOfferProduct();
        wop.setWebOfferId(offer.getId());
        wop.setEntityId(catalogId);
        wop.setRank(0);
        boolean exists = webOfferProductRepository.isExists(wop.getWebOfferId(), wop.getEntityId());
        if (!exists) {
            webOfferProductRepository.persist(wop);
        }

        preview.webOfferId = offer.getId();
        result.offersCreated++;
        result.productsLinked++;
        LOGGER.info("EmiImport: created web_offer id={} title='{}' catalogId={}", offer.getId(), title, catalogId);
    }

    private String inferOfferTypeSummary(List<EmiOfferImportDTO.Plan> plans) {
        Map<String, Integer> counts = new LinkedHashMap<>();
        for (EmiOfferImportDTO.Plan p : plans) {
            String ot = p.getOfferType();
            if (ot == null || ot.isEmpty()) continue;
            counts.merge(ot, 1, Integer::sum);
        }
        if (counts.isEmpty()) return "EMI";
        return counts.keySet().iterator().next(); // dominant/first offer type
    }

    private String buildDetailedText(EmiOfferImportDTO.Product product, EmiOfferImportDTO.Bank bank) {
        StringBuilder sb = new StringBuilder();
        sb.append(product.getProductName()).append(" · ").append(product.getPrice()).append("\n");
        for (EmiOfferImportDTO.Plan p : bank.getPlans()) {
            sb.append(nz(p.getTenure())).append("  ");
            sb.append(nz(p.getEmiAmount()));
            if (p.getOfferType() != null && !p.getOfferType().isEmpty()) {
                sb.append("  ").append(p.getOfferType());
            }
            if (p.getTotalCost() != null && !p.getTotalCost().isEmpty()) {
                sb.append("  total ").append(p.getTotalCost());
            }
            if (p.getInterestRate() != null && !p.getInterestRate().isEmpty()) {
                sb.append(" @").append(p.getInterestRate());
            }
            if (p.getDiscount() != null && !p.getDiscount().isEmpty()) {
                sb.append("  disc ").append(p.getDiscount());
            }
            sb.append("\n");
        }
        return sb.toString().trim();
    }

    private String nz(String s) {
        return s == null ? "" : s;
    }

    public static class ImportResult {
        public boolean dryRun;
        public String generatedAt;
        public int offersCreated;
        public int offersWouldCreate;
        public int productsLinked;
        public int banksSkippedNoPlans;
        public List<String> missingSkus = new ArrayList<>();
        public List<OfferPreview> previews = new ArrayList<>();
    }

    public static class OfferPreview {
        public String sku;
        public int catalogId;
        public int webOfferId;      // 0 when dry-run
        public String title;
        public String smallText;
        public String detailedText;
        public int planCount;
    }
}