package com.xxfc.platform.user.behavior.biz;

import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.xxfc.platform.activity.dto.ActivityListDTO;
import com.xxfc.platform.activity.dto.ActivityPopularizeRelationDTO;
import com.xxfc.platform.activity.feign.ActivityFeign;
import com.xxfc.platform.user.behavior.common.BehaviorEnum;
import com.xxfc.platform.user.behavior.dto.ActivityBehaviorDTO;
import com.xxfc.platform.user.behavior.dto.ActivityBehaviorRelationDTO;
import com.xxfc.platform.user.behavior.dto.BehaviorTypeDTO;
import com.xxfc.platform.user.behavior.dto.CustomerBehaviorNoteDTO;
import com.xxfc.platform.user.behavior.entity.CustomerBehaviorNotes;
import com.xxfc.platform.user.behavior.mapper.CustomerBehaviorNotesMapper;
import com.xxfc.platform.user.behavior.vo.BehaviorNoteCollectVo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * 用户行为记录表
 *
 * @author libin
 * @email 18178966185@163.com
 * @date 2019-08-12 14:03:55
 */
@Service
@RequiredArgsConstructor(onConstructor = @__({@Autowired}))
public class CustomerBehaviorNotesBiz extends BaseBiz<CustomerBehaviorNotesMapper, CustomerBehaviorNotes> {

    private final ActivityFeign activityFeign;

    private final BehaviorTypeBiz behaviorTypeBiz;

    private final ActivityBehaviorBiz activityBehaviorBiz;

    private final ActivityBehaviorRelationBiz activityBehaviorRelationBiz;

    public void saveCustomerBehavior(CustomerBehaviorNoteDTO customerBehaviorNoteDTO) {
        CustomerBehaviorNotes customerBehaviorNotes = new CustomerBehaviorNotes();
        BeanUtils.copyProperties(customerBehaviorNoteDTO, customerBehaviorNotes);
        customerBehaviorNotes.setCrtTime(Instant.now().toEpochMilli());
        mapper.insertSelective(customerBehaviorNotes);
    }

    public List<BehaviorNoteCollectVo> findBehaviorCollectByActivityId(Integer activityId, Long startTime, Long endTime) {

        List<BehaviorNoteCollectVo> behaviorNoteCollectVos = new ArrayList<>();

        //获取时间间隔
        AtomicLong startAtomic = new AtomicLong(startTime == null ? 0 : startTime);
        AtomicLong endAtomic = new AtomicLong(endTime == null ? 0 : endTime);
        long between_day = getBetweenDayAndprocessStartTimeAndEndTime(activityId, startAtomic, endAtomic);
        between_day = Math.abs(between_day) == 0 ? 1 : Math.abs(between_day);

        List<CustomerBehaviorNotes> customerBehaviorNotes = mapper.selectByActivityIdAndTime(activityId, startAtomic.get(), endAtomic.get());
        boolean isEmpty = CollectionUtils.isEmpty(customerBehaviorNotes);
        List<ActivityPopularizeRelationDTO> popularizeRelations = new ArrayList<>();
        Map<Integer, List<CustomerBehaviorNotes>> behaviorAndDataMap = null;
        if (!isEmpty) {
            //邀请成功记录
            popularizeRelations = activityFeign.findActivityPopularizeRelationByActivityIdAndTime(activityId, startAtomic.get(), endAtomic.get());
            behaviorAndDataMap = customerBehaviorNotes.stream().collect(Collectors.groupingBy(CustomerBehaviorNotes::getType, Collectors.toList()));
        }
        //根据活动id查询出对应业务id
        List<ActivityBehaviorRelationDTO> activityBehaviorRelations = activityBehaviorRelationBiz.findActivityBehaviorRelationsByActivityId(activityId);
        List<Integer> bizIds = activityBehaviorRelations.stream().map(ActivityBehaviorRelationDTO::getBizId).collect(Collectors.toList());

        //根据业务id查询出行为记录
        Map<Integer, List<CustomerBehaviorNotes>> behaviorTypeAndDataOfBizMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(bizIds)) {
            List<CustomerBehaviorNotes> customerBehaviorNotesbiz = mapper.selectAllByTypeIdsAndTime(bizIds, startAtomic.get(), endAtomic.get());
            //业务数据转换map
            if (CollectionUtils.isNotEmpty(customerBehaviorNotesbiz)) {
                behaviorTypeAndDataOfBizMap = customerBehaviorNotesbiz.stream().collect(Collectors.groupingBy(CustomerBehaviorNotes::getType, Collectors.toList()));
            }
        }
        //根据活动id查询活动行为
        List<ActivityBehaviorDTO> activityBehaviorDTOS = activityBehaviorBiz.findActivityBehaviorsByActivityId(activityId);
        if (CollectionUtils.isEmpty(activityBehaviorDTOS)){
            return Collections.EMPTY_LIST;
        }
        List<Integer> behaviorTypeIds = activityBehaviorDTOS.stream().map(ActivityBehaviorDTO::getBehaviorTypeId).collect(Collectors.toList());
        //根据活动行为ids查询行为
        List<BehaviorTypeDTO> behaviorTypeDTOS = behaviorTypeBiz.findBehaviorTypesByIds(behaviorTypeIds);
        List<Integer> behaviorCodes = behaviorTypeDTOS.stream().map(BehaviorTypeDTO::getCode).collect(Collectors.toList());
        //过滤出活动行为的枚举类
        Set<BehaviorEnum> behaviorEnums = EnumSet.allOf(BehaviorEnum.class).stream().filter(behaviorEnum -> behaviorCodes.contains(behaviorEnum.getCode())).collect(Collectors.toSet());
        //数据转换为行为码与行为名称Map
        Map<Integer, String> codeAndName = behaviorTypeDTOS.stream().collect(Collectors.toMap(BehaviorTypeDTO::getCode, BehaviorTypeDTO::getName));

        BehaviorNoteCollectVo behaviorNoteCollectVo;
        for (BehaviorEnum behaviorEnum : behaviorEnums) {
            behaviorNoteCollectVo = new BehaviorNoteCollectVo();
            behaviorNoteCollectVo.setBehavior(codeAndName.get(behaviorEnum.getCode()));
            long default_p_total, default_p_avg;
            ActionAcount actionAcount;
            switch (behaviorEnum) {
                case SUCCESS_INVIT:
                    actionAcount = new ActionAcount();
                    default_p_total = popularizeRelations.size();
                    default_p_avg = (default_p_total / between_day);
                    actionAcount.setDefault_p_total(default_p_total);
                    actionAcount.setDefault_p_avg(default_p_avg);
                    actionAcount.setDefault_u_total(default_p_total);
                    actionAcount.setDefault_u_avg(default_p_avg);
                    break;
                case SUCCESS_MORE_10_INVIT:
                    actionAcount = new ActionAcount();
                    default_p_total = popularizeRelations.stream().collect(Collectors.groupingBy(ActivityPopularizeRelationDTO::getMajorUserId, Collectors.counting())).values().stream().filter(x -> x >= 10).count();
                    default_p_avg = default_p_total / between_day;
                    actionAcount.setDefault_p_total(default_p_total);
                    actionAcount.setDefault_p_avg(default_p_avg);
                    actionAcount.setDefault_u_total(default_p_total);
                    actionAcount.setDefault_u_avg(default_p_avg);
                    break;
                case APP_VISIT_COUNT:
                    actionAcount = new ActionAcount();
                    default_p_total = mapper.selectAppVvisitsByType(BehaviorEnum.APP_VISIT_COUNT.getCode());
                    default_p_avg = default_p_total / between_day;
                    actionAcount.setDefault_p_total(default_p_total);
                    actionAcount.setDefault_p_avg(default_p_avg);
                    actionAcount.setDefault_u_total(default_p_total);
                    actionAcount.setDefault_u_avg(default_p_avg);
                    break;
                case BANNER_CLICK:
                case WONDERFUL_ACTIVITY_CLICK:
                case DIALOG_WINDOW_TO:
                case DIALOG_WINDOW:
                    actionAcount = new ActionAcount(between_day, behaviorTypeAndDataOfBizMap).invoke(behaviorEnum);
                    break;
                default:
                    actionAcount = new ActionAcount(between_day, behaviorAndDataMap).invoke(behaviorEnum);
                    break;
            }
            behaviorNoteCollectVo.setP_count(actionAcount.getDefault_p_total());
            behaviorNoteCollectVo.setP_avg_count(actionAcount.getDefault_p_avg());
            behaviorNoteCollectVo.setU_count(actionAcount.getDefault_u_total());
            behaviorNoteCollectVo.setU_avg_count(actionAcount.getDefault_u_avg());
            behaviorNoteCollectVos.add(behaviorNoteCollectVo);
        }
        return behaviorNoteCollectVos;
    }

    private long getBetweenDayAndprocessStartTimeAndEndTime(Integer activityId, AtomicLong startTime, AtomicLong endTime) {
        if (startTime.get() == 0 || endTime.get() == 0) {
            ActivityListDTO activityListDTO = activityFeign.findActivityStartTimeAndEndTimeById(activityId);
            Instant now = Instant.now();
            if (startTime.get() != 0) {
                endTime.set(now.toEpochMilli());
            }
            if (endTime.get() != 0) {
                startTime.set(activityListDTO.getActivity_startTime());
            }
            if (startTime.get() == 0 && endTime.get() == 0) {
                startTime.set(activityListDTO.getActivity_startTime());
                endTime.set(now.toEpochMilli());
            }
        }
        return ChronoUnit.DAYS.between(Instant.ofEpochMilli(startTime.get()), Instant.ofEpochMilli(endTime.get()));
    }

    private class ActionAcount {
        private long between_day;
        private Map<Integer, List<CustomerBehaviorNotes>> behaviorMap;
        private long default_p_total;
        private long default_p_avg;
        private long default_u_total;
        private long default_u_avg;

        public ActionAcount(long between_day, Map<Integer, List<CustomerBehaviorNotes>> behaviorMap) {
            this.between_day = between_day;
            this.behaviorMap = behaviorMap;
        }

        public ActionAcount() {
        }

        public ActionAcount invoke(BehaviorEnum behaviorEnum) {
            List<CustomerBehaviorNotes> behaviorTypeData = behaviorMap.get(behaviorEnum.getCode());
            boolean isEmpty = CollectionUtils.isEmpty(behaviorTypeData);
            default_p_total = isEmpty ? 0 : behaviorTypeData.size();
            default_p_avg = default_p_total / between_day;

            Set<CustomerBehaviorNotes> behaviorTypeDataSet = new HashSet<>(isEmpty ? Collections.EMPTY_SET : behaviorTypeData);
            default_u_total = behaviorTypeDataSet.size();
            default_u_avg = default_u_total / between_day;
            return this;
        }

        public long getDefault_p_total() {
            return default_p_total;
        }

        public long getDefault_p_avg() {
            return default_p_avg;
        }

        public long getDefault_u_total() {
            return default_u_total;
        }

        public long getDefault_u_avg() {
            return default_u_avg;
        }

        public void setBetween_day(long between_day) {
            this.between_day = between_day;
        }

        public void setBehaviorMap(Map<Integer, List<CustomerBehaviorNotes>> behaviorMap) {
            this.behaviorMap = behaviorMap;
        }

        public void setDefault_p_total(long default_p_total) {
            this.default_p_total = default_p_total;
        }

        public void setDefault_p_avg(long default_p_avg) {
            this.default_p_avg = default_p_avg;
        }

        public void setDefault_u_total(long default_u_total) {
            this.default_u_total = default_u_total;
        }

        public void setDefault_u_avg(long default_u_avg) {
            this.default_u_avg = default_u_avg;
        }
    }
}