
package com.tmerclub.cloud.flow.service.impl;

import cn.hutool.core.date.DateUtil;
import com.tmerclub.cloud.flow.bo.FlowSystemUserBO;
import com.tmerclub.cloud.flow.service.SystemUserAnalyseMongoService;
import com.tmerclub.cloud.flow.util.FlowUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * 流量分析—用户访问数据
 *
 * @author YXF
 * @date 2021-05-21 15:25:19
 */
@Service
public class SystemUserAnalyseMongoServiceImpl implements SystemUserAnalyseMongoService {

    private static final Logger LOG = LoggerFactory.getLogger(SystemUserAnalyseMongoServiceImpl.class);

    @Autowired
    private MongoTemplate mongoTemplate;

    private final static String[] SYSTEM_TYPE = {"全部", "PC", "H5", "微信小程序", "安卓", "IOS"};

    @Override
    public void statisticsAndSaveSystemUserOfDay(Integer dateType, Date beginDate, Date endDate) {

        // 获取每个端的访问用户数据列表
        List<FlowSystemUserBO> systemUserAnalyseList = this.insertSystemUserList(beginDate, endDate);

        String date = DateUtil.format(beginDate, "yyMMdd");
        int i = 1;

        for (FlowSystemUserBO flowSystemUserBO : systemUserAnalyseList) {
            flowSystemUserBO.setDateType(dateType);
            flowSystemUserBO.setCreateTime(beginDate);
            flowSystemUserBO.setId(FlowUtil.getId(date + dateType + flowSystemUserBO.getSystemType(), i++));
        }

        // 批量保存各系统用户列表数据
        this.batchInsertFlowSystemUserBO(beginDate, endDate, systemUserAnalyseList);
    }

    private void batchInsertFlowSystemUserBO(Date beginDate, Date endDate, List<FlowSystemUserBO> systemUserAnalyseList) {
        Long beginId = FlowUtil.timeToId(beginDate);
        Long endId = FlowUtil.timeToId(endDate);

        // 先删除再更新-mongo没有事务，如果之前保存后程序报错了，数据还是保存在数据库中
        mongoTemplate.remove(new Query(Criteria.where("_id").gte(beginId).lt(endId)), FlowSystemUserBO.class);
        // 统计的数据批量保存到flow_system_user
        mongoTemplate.insertAll(systemUserAnalyseList);
    }

    private List<FlowSystemUserBO> insertSystemUserList(Date beginDate, Date endDate) {
        MatchOperation matchOperation = Aggregation.match(Criteria.where("dt").gte(beginDate).lt(endDate));

        GroupOperation userGroupOperation = Aggregation.group("oid", "st", "ve")
                .first("ve").as("ve")
                .last("uid").as("uid")
                .max("s").as("step");

        ProjectionOperation userProjectionOperation = Aggregation.project("st")
                .and(ConditionalOperators.when(Criteria.where("step").gt(1)).then(1).otherwise(0)).as("loss")
                .and(ConditionalOperators.when(Criteria.where("uid").gt(0)).then(1).otherwise(0)).as("newVisitUser")
                .and(ConditionalOperators.when(Criteria.where("ve").is(2)).then(1).otherwise(0)).as("plusShopCart")
                .and(ConditionalOperators.when(Criteria.where("ve").is(4)).then(1).otherwise(0)).as("placeOrder")
                .and(ConditionalOperators.when(Criteria.where("ve").is(5)).then(1).otherwise(0)).as("pay")
                .and(ConditionalOperators.when(Criteria.where("uid").gt(0)).then("$uid").otherwise("$_id.oid")).as("uid");


        GroupOperation systemGroupOperation = Aggregation.group("st", "uid")
                .max("loss").as("loss")
                .max("newVisitUser").as("newVisitUser")
                .max("plusShopCart").as("plusShopCart")
                .max("placeOrder").as("placeOrder")
                .max("pay").as("pay")
                .first("st").as("systemType")
                .first("uid").as("userId");


        ProjectionOperation projectionOperation = Aggregation.project("plusShopCart", "placeOrder", "pay","systemType", "userId")
                .andExclude("_id")
                .and(ConditionalOperators.when(Criteria.where("loss").is(1)).then(0).otherwise(1)).as("loss")
                .and(ConditionalOperators.when(Criteria.where("newVisitUser").is(1)).then(0).otherwise(1)).as("newVisitUser");


        TypedAggregation<FlowSystemUserBO> typedAggregation = Aggregation.newAggregation(
                FlowSystemUserBO.class,
                matchOperation,
                userGroupOperation,
                userProjectionOperation,
                systemGroupOperation,
                Aggregation.unwind("_id"),
                projectionOperation
        );

        LOG.info("insertSystemUserList.typedAggregation:{}", typedAggregation);

        List<FlowSystemUserBO> systemUserAnalyseList = mongoTemplate
                .aggregate(typedAggregation, "flow_user_log", FlowSystemUserBO.class)
                .getMappedResults();
        return systemUserAnalyseList;
    }
}
