package com.softwarebr.nunu.service.go.impl;

import com.brframework.common.utils.DateTimeUtils;
import com.brframework.commondb.core.AbstractEntityService;
import com.brframework.commondb.core.CommonRepository;
import com.brframework.commondb.core.ControllerPageHandle;
import com.brframework.commonweb.exception.HandleException;
import com.brframework.commonweb.json.PageParam;
import com.google.common.collect.Lists;
import com.softwarebr.nunu.dao.go.PolicyDao;
import com.softwarebr.nunu.domain.VisualizationDate;
import com.softwarebr.nunu.dto.go.PolicyLabelParamDTO;
import com.softwarebr.nunu.dto.go.PolicyParamDTO;
import com.softwarebr.nunu.entity.go.Policy;
import com.softwarebr.nunu.entity.go.PolicyLabel;
import com.softwarebr.nunu.globals.SystemConst;
import com.softwarebr.nunu.json.admin.visual.PolicyCollectionResult;
import com.softwarebr.nunu.service.go.PolicyLabelService;
import com.softwarebr.nunu.service.go.PolicyService;
import com.softwarebr.nunu.util.VisualizationUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.stream.Collectors;

import static com.softwarebr.nunu.entity.go.Policy.APPLY_STATUS_DISPLAY;

/**
 * @author lilin
 * @date 2020-02-19 15:35:44
 */

@Slf4j
@Service
public class PolicyServiceImpl extends AbstractEntityService<Policy, Long, Object> implements PolicyService {

    @Autowired
    private PolicyDao policyDao;
    @Autowired
    private PolicyLabelService policyLabelService;
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public CommonRepository<Long, Policy> getRepository() {
        return policyDao;
    }

    @Override
    public Page<Policy> relativePage(PageParam page, List<PolicyLabel> policyLabel) {
        if (policyLabel == null || policyLabel.size() == 0) {
            throw new HandleException("标签列表必须不为空!");
        }
        StringBuilder listSql = new StringBuilder();
        StringBuilder countSql = new StringBuilder();
        String childIds = StringUtils.join(policyLabel.stream().map(PolicyLabel::getChildId).collect(Collectors.toList()), ",");
        String from = "FROM go_policy po join (select DISTINCT pl_1.policy_id from go_policy_label pl_1 WHERE pl_1.child_id in (" + childIds + ")) pl on po.id = pl.policy_id " +
                "where verify = " + SystemConst.VERIFY_ADOPT + " and marker = " + SystemConst.MARKER_STATUS_NO;
        listSql.append("SELECT po.* " + from + " order by create_date desc ");
        countSql.append("SELECT count(po.id) " + from);

        Query countQuery = entityManager.createNativeQuery(countSql.toString());
        long total = ((BigInteger) countQuery.getSingleResult()).longValue();
        Query query = entityManager.createNativeQuery(listSql.toString(), Policy.class);

        query.setFirstResult(page.getPageIndex());
        query.setMaxResults(page.getPageSize());
        List<Policy> resultList = query.getResultList();
        return new PageImpl<>(resultList, Pageable.unpaged(), total);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void savePolicy(PolicyParamDTO policyParamDTO, List<PolicyLabelParamDTO> labelParamDTOS) {
        Policy policy = ControllerPageHandle.convertTo(policyParamDTO, Policy.class);
        policy.setCreateDate(LocalDateTime.now());
        policy.setMarker(SystemConst.MARKER_STATUS_NO);
        policy.setPublishDate(LocalDateTime.now());
        policy.setIndexType(SystemConst.INDEX_TYPE_NO);
        policy.setStatus(SystemConst.STATUS_LOWER_SHELF);
        policy.setSource("平台");
        policy.setSourceType(Policy.SOURCE_TYPE_ADMIN);
        policy.setVerify(SystemConst.VERIFY_ADOPT);
        policy = policyDao.save(policy);
        for (PolicyLabelParamDTO policyParam : labelParamDTOS) {
            policyLabelService.save(PolicyLabel.builder()
                    .createDate(LocalDateTime.now())
                    .parentId(policyParam.getParentLevelId())
                    .policyId(policy.getId())
                    .childId(policyParam.getChildLevelId()).build());
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePolicy(Long policyId, PolicyParamDTO policyParamDTO, List<PolicyLabelParamDTO> labelParamDTOS) {
        Policy policy = accessObject(policyId);
        policy.setTitle(policyParamDTO.getTitle());
        policy.setContent(policyParamDTO.getContent());
        policy.setProvinceId(policyParamDTO.getProvinceId());
        policy.setCityId(policyParamDTO.getCityId());
        policy.setAreaId(policyParamDTO.getAreaId());
        policyDao.save(policy);
        policyLabelService.removeByPolicyId(policyId);
        for (PolicyLabelParamDTO policyParam : labelParamDTOS) {
            policyLabelService.save(PolicyLabel.builder()
                    .createDate(LocalDateTime.now())
                    .parentId(policyParam.getParentLevelId())
                    .policyId(policyId)
                    .childId(policyParam.getChildLevelId()).build());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removePolicyById(Long policyId) {
        Policy policy = accessObject(policyId);
        policy.setMarker(SystemConst.MARKER_STATUS_YES);
        policyDao.save(policy);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePolicyVerify(Long policyId, Integer verify, String remark) {
        Policy policy = accessObject(policyId);
        if (!policy.getVerify().equals(SystemConst.VERIFY_AWAIT)) {
            throw new HandleException("政策已审核，请勿重复操作");
        }
        policy.setVerify(verify);
        policy.setRemark(remark);
        policyDao.save(policy);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void policyUpperShelf(Long policyId) {
        Policy policy = accessObject(policyId);
        if (policy.getStatus().equals(SystemConst.STATUS_UPPER_SHELF)) {
            throw new HandleException("政策已上架，请勿重复操作");
        }
        policy.setStatus(SystemConst.STATUS_UPPER_SHELF);
        policyDao.save(policy);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void policyLowerShelf(Long policyId) {
        Policy policy = accessObject(policyId);
        if (policy.getStatus().equals(SystemConst.STATUS_LOWER_SHELF)) {
            throw new HandleException("政策已下架，请勿重复操作");
        }
        policy.setStatus(SystemConst.STATUS_LOWER_SHELF);
        policyDao.save(policy);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void policyIndexYes(Long policyId) {
        Policy policy = accessObject(policyId);
        if (policy.getIndexType().equals(SystemConst.INDEX_TYPE_YES)) {
            throw new HandleException("政策已推荐至首页，请勿重复操作");
        }
        policy.setIndexType(SystemConst.INDEX_TYPE_YES);
        policyDao.save(policy);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void policyIndexNo(Long policyId) {
        Policy policy = accessObject(policyId);
        if (policy.getIndexType().equals(SystemConst.INDEX_TYPE_NO)) {
            throw new HandleException("政策已取消推荐至首页，请勿重复操作");
        }
        policy.setIndexType(SystemConst.INDEX_TYPE_NO);
        policyDao.save(policy);
    }


    @Override
    public void saveSpiderPolicy(String source, String title, String content, LocalDateTime publishTime) {
        save(Policy.builder()
                .createDate(LocalDateTime.now())
                .publishDate(publishTime)
                .source(source)
                .title(title)
                .content(content)
                .sourceType(Policy.SOURCE_TYPE_REPTILE)
                .indexType(SystemConst.INDEX_TYPE_NO)
                .status(SystemConst.STATUS_LOWER_SHELF)
                .verify(SystemConst.VERIFY_AWAIT)
                .applyStatus(APPLY_STATUS_DISPLAY)
                .marker(SystemConst.MARKER_STATUS_NO)
                .build());

    }


    @Override
    public boolean checkPolicy(String source, String title) {
        if (policyDao.countBySourceAndTitle(source, title) > 0) {
            return true;
        }
        return false;
    }

    @Override
    public List<PolicyCollectionResult> getPolicyCollectionTotal(String minDateTime, String maxDateTime, Long days) {
        VisualizationDate visual = VisualizationUtil.visualDateHandle(minDateTime, maxDateTime, days);
        List<PolicyCollectionResult> projectResults = Lists.newArrayList();
        for (long i = 0; i <= visual.getDays(); i++) {
            PolicyCollectionResult policyResult = new PolicyCollectionResult();
            LocalDateTime startDate = visual.getMaxDate().minusDays(i).with(LocalTime.MIN);
            LocalDateTime endDate = visual.getMaxDate().minusDays(i).with(LocalTime.MAX);
            policyResult.setPolicyTotal(policyDao.countByMarkerAndCreateDateBetween(SystemConst.MARKER_STATUS_NO, startDate, endDate));
            policyResult.setVisualDate(visual.getMaxDate().minusDays(i).format(DateTimeUtils.FORMATTER_DEFAULT_YMD));
            projectResults.add(policyResult);
        }
        return projectResults;
    }

}