package com.jh.radegast.rating;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.jh.common.utils.Utils;
import com.jh.common.web.list.Page;
import com.jh.common.web.list.PagingInfo;
import com.jh.radegast.api.RatingsFilter;
import com.jh.radegast.api.RatingsStats;
import com.jh.radegast.model.Rating;
import com.jh.radegast.model.RatingStat;

@Service
public class RatingService {

	private static final Logger LOG = LoggerFactory.getLogger(RatingService.class);
		
	
	@Autowired
	private RatingRepository repo;

	
	@Transactional
	public void saveBulk(Collection<Rating> ratings) {
		if (ratings == null || ratings.isEmpty()) {
			return;
		}
		
		Map<String, Rating> ratingsToSave = new HashMap<>();
		for (Rating r : ratings) {
			ratingsToSave.put(r.getKey(), r);
		}

		List<Rating> existing = repo.fetchByKeys(ratingsToSave.keySet());
		if (existing != null && !existing.isEmpty()) {
			StringJoiner sj = new StringJoiner(", ");
			int duplicated = 0;
			
			for (Rating r : existing) {
				ratingsToSave.remove(r.getKey());
				sj.add(r.getKey());
				duplicated++;
			}
			
			LOG.info("Ignoring {} duplicated records: {}", duplicated, sj);
		}
		
		Collection<Rating> values = ratingsToSave.values();
		LOG.info("Storing {} ratings", values.size());
		repo.saveBulk(values);
	}


	@Transactional
	public Page<Rating> filter(RatingsFilter ratingsFilter, PagingInfo pagingInfo) {
		return repo.filter(ratingsFilter, pagingInfo);
	}

	
	@Transactional
	public List<Rating> filter(RatingsFilter ratingsFilter) {
		return repo.filter(ratingsFilter);
	}
	
	@Transactional
	public RatingsStats calculateStats(RatingsFilter filter) {
		
		Long total = 0L;
		Long value = 0L;
		BigDecimal average = BigDecimal.ZERO;
		HashMap<Long, Long> ratings = new LinkedHashMap<>();

		for (int i = 10; i > 0; i--) {
			ratings.put(Long.valueOf(i), 0L);
		}
		
		List<RatingStat> list = repo.stats(filter);
		if (list != null) {
			for (RatingStat rs : list) {
				ratings.put(rs.getRating(), rs.getCount());
				total += rs.getCount();
				value += rs.getRating() * rs.getCount();
			}
		}
		
		if (total > 0) {
			average = Utils.divide(new BigDecimal(value), new BigDecimal(total), 2);
		}
		
		return new RatingsStats(total, average, ratings);
	}
	
}
