package com.iformall.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.IdWorker;
import com.iformall.common.ResultData;
import com.iformall.domain.dto.WxCUserBasicInfoDto;
import com.iformall.domain.dto.WxCUserBasicInfoFilterDto;
import com.iformall.domain.dto.WxCUserBasicInfoFilterListDto;
import com.iformall.domain.po.*;
import com.iformall.domain.vo.*;
import com.iformall.enums.*;
import com.iformall.mapper.*;
import com.iformall.service.*;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class WxCUserBasicInfoServiceImpl implements WxCUserBasicInfoService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    WxCUserTagsMapper wxCUserTagsMapper;

    @Autowired
    WxCUserBasicInfoMapper wxCUserBasicInfoMapper;

    @Autowired
    WxCUserMapper wxCUserMapper;

    @Autowired
    WxTagsMapper wxTagsMapper;

    @Autowired
    WxScoreHistoryMapper scoreHistoryMapper;

    @Autowired
    WxCreditHistoryMapper creditHistoryMapper;

    @Autowired
    WxCUserTagsService wxCUserTagsService;

    @Autowired
    WxScoreRulesService wxScoreRulesService;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    WxCarPayRecordMapper wxCarPayRecordMapper;

    @Autowired
    ExcelService excelService;

    @Autowired
    WxCreditHistoryService wxCreditHistoryService;

    @Autowired
    WxLevelConfigService wxLevelConfigService;

    @Autowired
    WxTagsService wxTagsService;


    /***************user filter start******************************************/

    private final static List<WxTags> memberTimeList = new ArrayList<WxTags>(
            Arrays.asList(
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1000.getMessage());
                        setId(EnumTag.ID_1000.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1001.getMessage());
                        setId(EnumTag.ID_1001.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1002.getMessage());
                        setId(EnumTag.ID_1002.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1003.getMessage());
                        setId(EnumTag.ID_1003.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1004.getMessage());
                        setId(EnumTag.ID_1004.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1005.getMessage());
                        setId(EnumTag.ID_1005.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1006.getMessage());
                        setId(EnumTag.ID_1006.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1007.getMessage());
                        setId(EnumTag.ID_1007.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1008.getMessage());
                        setId(EnumTag.ID_1008.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1009.getMessage());
                        setId(EnumTag.ID_1009.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1010.getMessage());
                        setId(EnumTag.ID_1010.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_50.getCode());
                        setName(EnumTag.ID_1011.getMessage());
                        setId(EnumTag.ID_1011.getCode());
                    }}
            )
    );

    private final static String RANGE_START = "rangeStart";
    private final static String RANGE_END = "rangeEnd";

    private final static Map<Long,Map<String,Long>> memberTimeMap
            = new HashMap<Long,Map<String,Long>>() {
        {
            put(EnumTag.ID_1000.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,0L);
                        put(RANGE_END,1L);
                    }});
            put(EnumTag.ID_1001.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,0L);
                        put(RANGE_END,7L);
                    }});
            put(EnumTag.ID_1002.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,0L);
                        put(RANGE_END,30L);
                    }});
            put(EnumTag.ID_1003.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,0L);
                        put(RANGE_END,90L);
                    }});
            put(EnumTag.ID_1004.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,0L);
                        put(RANGE_END,365L);
                    }});
            put(EnumTag.ID_1005.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,0L);
                        put(RANGE_END,365*5L);
                    }});
            put(EnumTag.ID_1006.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,365*5L);
                    }});
            put(EnumTag.ID_1007.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,365L);
                    }});
            put(EnumTag.ID_1008.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,90L);
                    }});
            put(EnumTag.ID_1009.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,30L);
                    }});
            put(EnumTag.ID_1010.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,7L);
                    }});
            put(EnumTag.ID_1011.getCode(),
                    new HashMap<String,Long>(){{
                        put(RANGE_START,1L);
                    }});
        }
    };

    private final static List<WxTags> memberBirthday = new ArrayList<WxTags>(
            Arrays.asList(
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_52.getCode());
                        setName(EnumTag.ID_1100.getMessage());
                        setId(EnumTag.ID_1100.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_52.getCode());
                        setName(EnumTag.ID_1101.getMessage());
                        setId(EnumTag.ID_1101.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_52.getCode());
                        setName(EnumTag.ID_1102.getMessage());
                        setId(EnumTag.ID_1102.getCode());
                    }}
            )
    );

    private final static List<WxTags> memberLoginActivity = new ArrayList<WxTags>(
            Arrays.asList(
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_53.getCode());
                        setName(EnumTag.ID_1200.getMessage());
                        setId(EnumTag.ID_1200.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_53.getCode());
                        setName(EnumTag.ID_1201.getMessage());
                        setId(EnumTag.ID_1201.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_53.getCode());
                        setName(EnumTag.ID_1202.getMessage());
                        setId(EnumTag.ID_1202.getCode());
                    }}
            )
    );

    private final static List<WxTags> memberCouponVerified = new ArrayList<WxTags>(
            Arrays.asList(
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_54.getCode());
                        setName(EnumTag.ID_1300.getMessage());
                        setId(EnumTag.ID_1300.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_54.getCode());
                        setName(EnumTag.ID_1301.getMessage());
                        setId(EnumTag.ID_1301.getCode());
                    }},
                    new WxTags(){{
                        setTypeId(EnumTagType.ID_54.getCode());
                        setName(EnumTag.ID_1302.getMessage());
                        setId(EnumTag.ID_1302.getCode());
                    }}
            )
    );

    private void filtersToDtoID0(WxCUserBasicInfoDto dto, WxCUserBasicInfoFilterDto f) {
        dto.setPhones(f.getParam());
    }

    private void filtersToDtoID50(WxCUserBasicInfoDto dto, WxCUserBasicInfoFilterDto f) {
        ZoneId zone = ZoneId.systemDefault();

        Map<String,Long> rangeMap = memberTimeMap.get(f.getId());
        if (rangeMap != null) {
            Long rangeEnd = rangeMap.get(RANGE_END);
            if (rangeEnd != null) {
                LocalDateTime localDateTimeStart = LocalDateTime.now().minusDays(rangeEnd);
                dto.setStartTime(Date.from(localDateTimeStart.atZone(zone).toInstant()));
            }
            Long rangeStart = rangeMap.get(RANGE_START);
            if (rangeStart != null) {
                LocalDateTime localDateTimeEnd = LocalDateTime.now().minusDays(rangeStart);
                dto.setEndTime(Date.from(localDateTimeEnd.atZone(zone).toInstant()));
            }
        }
    }
    private void filtersToDtoID51(WxCUserBasicInfoDto dto, WxCUserBasicInfoFilterDto f) {
        List<WxLevelConfig> levels = wxLevelConfigService.getByTenantId(dto.getTenantId());
        if (f.getId().equals(0L)) {
            dto.setLevelStartScore(0);
            if (levels.isEmpty())
                dto.setLevelEndScore(null);
            else
                dto.setLevelEndScore(levels.get(0).getPoints());
        } else {
            for (int i = 0; i < levels.size(); i++) {
                WxLevelConfig l = levels.get(i);
                if (l.getId().equals(f.getId())) {
                    dto.setLevelStartScore(l.getPoints());
                    if (i + 1 < levels.size())
                        dto.setLevelEndScore(levels.get(i + 1).getPoints());
                    else
                        dto.setLevelEndScore(null);
                    break;
                }
            }
        }
    }

    private void filtersToDtoID52(WxCUserBasicInfoDto dto, WxCUserBasicInfoFilterDto f) {
        LocalDate localDate = LocalDate.now();
        ZoneId zone = ZoneId.systemDefault();
        if (f.getId().equals(EnumTag.ID_1100.getCode())) {
            dto.setBirthStartTime(
                    Date.from(
                            localDate.atStartOfDay().atZone(zone).toInstant()));
            dto.setBirthEndTime(
                    Date.from(
                            localDate.plusDays(1).atStartOfDay().atZone(zone).toInstant()));
        } else if (f.getId().equals(EnumTag.ID_1101.getCode())){
            dto.setBirthStartTime(
                    Date.from(
                            localDate.with(DayOfWeek.MONDAY).atStartOfDay().atZone(zone).toInstant()));
            dto.setBirthEndTime(
                    Date.from(
                            localDate.plusWeeks(1).with(DayOfWeek.MONDAY).atStartOfDay().atZone(zone).toInstant()));
        } else if (f.getId().equals(EnumTag.ID_1102.getCode())){
            dto.setBirthStartTime(
                    Date.from(
                            localDate.with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay().atZone(zone).toInstant()));
            dto.setBirthEndTime(
                    Date.from(
                            localDate.plusMonths(1).with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay().atZone(zone).toInstant()));
        }
    }

    private void filtersToDtoID53(WxCUserBasicInfoDto dto, WxCUserBasicInfoFilterDto f) {
        LocalDate localDate = LocalDate.now();
        ZoneId zone = ZoneId.systemDefault();
        if (f.getId().equals(EnumTag.ID_1200.getCode())) {
            dto.setLoginStartTime(
                    Date.from(
                            localDate.atStartOfDay().atZone(zone).toInstant()));
            dto.setLoginEndTime(
                    Date.from(
                            localDate.plusDays(1).atStartOfDay().atZone(zone).toInstant()));
        } else if (f.getId().equals(EnumTag.ID_1201.getCode())){
            dto.setLoginStartTime(
                    Date.from(
                            localDate.with(DayOfWeek.MONDAY).atStartOfDay().atZone(zone).toInstant()));
            dto.setLoginEndTime(
                    Date.from(
                            localDate.plusWeeks(1).with(DayOfWeek.MONDAY).atStartOfDay().atZone(zone).toInstant()));
        } else if (f.getId().equals(EnumTag.ID_1202.getCode())){
            dto.setLoginStartTime(
                    Date.from(
                            localDate.with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay().atZone(zone).toInstant()));
            dto.setLoginEndTime(
                    Date.from(
                            localDate.plusMonths(1).with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay().atZone(zone).toInstant()));
        }
    }

    private void filtersToDtoID54(WxCUserBasicInfoDto dto, WxCUserBasicInfoFilterDto f) {
        LocalDate localDate = LocalDate.now();
        ZoneId zone = ZoneId.systemDefault();
        if (f.getId().equals(EnumTag.ID_1300.getCode())) {
            dto.setVerifiedStartTime(
                    Date.from(
                            localDate.atStartOfDay().atZone(zone).toInstant()));
            dto.setVerifiedEndTime(
                    Date.from(
                            localDate.plusDays(1).atStartOfDay().atZone(zone).toInstant()));
        } else if (f.getId().equals(EnumTag.ID_1301.getCode())){
            dto.setVerifiedStartTime(
                    Date.from(
                            localDate.with(DayOfWeek.MONDAY).atStartOfDay().atZone(zone).toInstant()));
            dto.setVerifiedEndTime(
                    Date.from(
                            localDate.plusWeeks(1).with(DayOfWeek.MONDAY).atStartOfDay().atZone(zone).toInstant()));
        } else if (f.getId().equals(EnumTag.ID_1302.getCode())){
            dto.setVerifiedStartTime(
                    Date.from(
                            localDate.with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay().atZone(zone).toInstant()));
            dto.setVerifiedEndTime(
                    Date.from(
                            localDate.plusMonths(1).with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay().atZone(zone).toInstant()));
        }
    }

    private WxCUserBasicInfoDto filtersToDto(String tenantId, List<WxCUserBasicInfoFilterDto> filterList){
        WxCUserBasicInfoDto dto = new WxCUserBasicInfoDto();
        List<Long> tagIdList = new ArrayList<>();

        filterList.stream().forEach(f->{
            if (f.getTypeId()==null) {
                tagIdList.add(f.getId());
                return;
            }
            if(f.getTypeId().equals(EnumTagType.ID_0.getCode())) {
                filtersToDtoID0(dto,f);
            } else if(f.getTypeId().equals(EnumTagType.ID_50.getCode())) {
                filtersToDtoID50(dto,f);
            } else if (f.getTypeId().equals(EnumTagType.ID_51.getCode())) {
                filtersToDtoID51(dto,f);
            } else if (f.getTypeId().equals(EnumTagType.ID_52.getCode())) {
                filtersToDtoID52(dto,f);
            } else if (f.getTypeId().equals(EnumTagType.ID_53.getCode())) {
                filtersToDtoID53(dto,f);
            } else if (f.getTypeId().equals(EnumTagType.ID_54.getCode())) {
                filtersToDtoID54(dto,f);
            } else {
                tagIdList.add(f.getId());
            }
        });
        if(!tagIdList.isEmpty())
            dto.setTagIds(tagIdList);
        dto.setTenantId(tenantId);
        return dto;
    }

    private WxTagsTypeVo generateType50() {
        WxTagsTypeVo type = new WxTagsTypeVo();
        type.setFlag(EnumTagTypeFlag.FLAG_SINGLE.getCode());
        type.setName(EnumTagType.ID_50.getMessage());
        type.setId(EnumTagType.ID_50.getCode());
        type.setTags(memberTimeList);
        return type;
    }

    private WxTagsTypeVo generateType51(String tenentId) {
        WxTagsTypeVo type = new WxTagsTypeVo();
        type.setFlag(EnumTagTypeFlag.FLAG_SINGLE.getCode());
        type.setName(EnumTagType.ID_51.getMessage());
        type.setId(EnumTagType.ID_51.getCode());

        List<WxTags> tagsMemberLevel = new ArrayList<>();
        List<WxLevelConfig> levels = wxLevelConfigService.getByTenantId(tenentId);

        WxTags wxTagsBase = new WxTags();
        wxTagsBase.setName(WxLevelConfigService.DEFAULT_LEVEL);
        wxTagsBase.setTypeId(EnumTagType.ID_51.getCode());
        wxTagsBase.setId(0L);
        tagsMemberLevel.add(wxTagsBase);

        levels.stream().forEach(l->{
            WxTags wxTags = new WxTags();
            wxTags.setName(l.getLevel());
            wxTags.setId(l.getId());
            wxTags.setTypeId(EnumTagType.ID_51.getCode());
            tagsMemberLevel.add(wxTags);
        });
        type.setTags(tagsMemberLevel);
        return type;
    }

    private WxTagsTypeVo generateType52() {
        WxTagsTypeVo type = new WxTagsTypeVo();
        type.setFlag(EnumTagTypeFlag.FLAG_SINGLE.getCode());
        type.setName(EnumTagType.ID_52.getMessage());
        type.setId(EnumTagType.ID_52.getCode());
        type.setTags(memberBirthday);
        return type;
    }

    private WxTagsTypeVo generateType53() {
        WxTagsTypeVo type = new WxTagsTypeVo();
        type.setFlag(EnumTagTypeFlag.FLAG_SINGLE.getCode());
        type.setName(EnumTagType.ID_53.getMessage());
        type.setId(EnumTagType.ID_53.getCode());
        type.setTags(memberLoginActivity);
        return type;
    }

    private WxTagsTypeVo generateType54() {
        WxTagsTypeVo type = new WxTagsTypeVo();
        type.setFlag(EnumTagTypeFlag.FLAG_SINGLE.getCode());
        type.setName(EnumTagType.ID_54.getMessage());
        type.setId(EnumTagType.ID_54.getCode());
        type.setTags(memberCouponVerified);
        return type;
    }

    public List<WxTagsGroupVo> listFilters(String tenantId) {
        WxTagsGroupVo filter = new WxTagsGroupVo();

        filter.setId(EnumTagGroup.ID_10.getCode());
        filter.setName(EnumTagGroup.ID_10.getMessage());

        List<WxTagsTypeVo> types = new ArrayList<>();
        types.add(generateType50());
        types.add(generateType51(tenantId));
        types.add(generateType52());
        types.add(generateType53());
        types.add(generateType54());
        filter.setTypes(types);
        List<WxTagsGroupVo> listVo =wxTagsService.listAllVo();
        listVo.add(0,filter);
        return listVo;
    }


    public long countByFilter(String tenantId, List<WxCUserBasicInfoFilterDto> filterList) {
        return wxCUserBasicInfoMapper.findCountByFilter(filtersToDto(tenantId,filterList));
    }

    public List<WxCUserBasicInfo> listByFilter(String tenantId, List<WxCUserBasicInfoFilterDto> filterList) {
        return wxCUserBasicInfoMapper.findListByFilter(filtersToDto(tenantId,filterList));
    }
    @Override
    public List<WxCUserBasicInfo> listByFilterList(String tenantId, List<WxCUserBasicInfoFilterListDto> filterList) {
        HashSet<WxCUserBasicInfo> userSet = new HashSet<>();
        filterList.stream().forEach(f->userSet.addAll(listByFilter(tenantId,f.getTagList())));
        return new ArrayList<>(userSet);
    }



    /***************user filter end******************************************/

    @Override
    public PageInfo<WxCUserBasicInfo> listAsPage(WxCUserBasicInfo record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxCUserBasicInfoMapper.findList(record));
    }

    @Override
    public int countUser(WxCUserBasicInfo record) {
        return wxCUserBasicInfoMapper.selectCount(new QueryWrapper(record));
    }

    @Override
    public List<WxCUserBasicInfo> findByPhone(String tenantId, String phone) {
        WxCUserBasicInfo basicQ = new WxCUserBasicInfo();
        basicQ.setTenantId(tenantId);
        basicQ.setPhone(phone);
        List<WxCUserBasicInfo> basicInfos = wxCUserBasicInfoMapper.selectList(new QueryWrapper(basicQ));
        if (basicInfos != null && basicInfos.size() > 0) {
            WxCUserBasicInfo wxCUserBasicInfo = basicInfos.get(0);
            if (wxCUserBasicInfo.getPoins() != null) {
                List<WxLevelConfig> levelList = wxLevelConfigService.getByTenantId(wxCUserBasicInfo.getTenantId());
                String level = WxLevelConfigService.DEFAULT_LEVEL;
                for(WxLevelConfig levelConfig: levelList) {
                    if (wxCUserBasicInfo.getPoins() >= levelConfig.getPoints()) {
                        level = levelConfig.getLevel();
                    }
                }
                wxCUserBasicInfo.setLevel(level);
                List<WxCUserBasicInfo> basicInfoList = Lists.newArrayList();
                basicInfoList.add(wxCUserBasicInfo);
                return basicInfoList;
            }
        }
        return basicInfos;
    }

    @Override
    public WxCUserBasicInfo findInfoByPhone(String tenantId, String phone) {
        WxCUserBasicInfo basic = null;
        WxCUserBasicInfo basicQ = new WxCUserBasicInfo();
        basicQ.setTenantId(tenantId);
        basicQ.setPhone(phone);
        List<WxCUserBasicInfo> basicInfos = wxCUserBasicInfoMapper.selectList(new QueryWrapper(basicQ));
        if (basicInfos.size() > 0) {
            return basicInfos.get(0);
        }
        return basic;
    }

    @Override
    public void updateScore(WxCUserBasicInfo record) {
        wxCUserBasicInfoMapper.updateScore(record);
    }

    @Override
    public WxCUserBasicInfo getById(Long id) {
        return wxCUserBasicInfoMapper.selectById(id);
    }

    @Override
    public void save(WxCUserBasicInfo record) {
        wxCUserBasicInfoMapper.insert(record);
    }

    @Override
    public void update(WxCUserBasicInfo record) {
        wxCUserBasicInfoMapper.updateById(record);
    }

    @Override
    public void updateObj(WxCUserBasicInfo record, WxCUser user) {
        // 1. update c_user_tags
        CUserTagNewIdVo userTagVo = new CUserTagNewIdVo();
        userTagVo.setTenantId(record.getTenantId());
        userTagVo.setUserId(record.getId());
        userTagVo.setNewUserId(user.getId());
        wxCUserTagsMapper.updateNewId(userTagVo);

        // 2. update score history
        WxScoreHistoryNewIdVo scoreHistoryNewIdVo = new WxScoreHistoryNewIdVo();
        scoreHistoryNewIdVo.setTenantId(record.getTenantId());
        scoreHistoryNewIdVo.setCUserId(record.getId());
        scoreHistoryNewIdVo.setNewUserId(user.getId());
        scoreHistoryMapper.updateNewId(scoreHistoryNewIdVo);

        // 3. update credit history
        WxCreditHistoryNewIdVo creditHistoryNewIdVo = new WxCreditHistoryNewIdVo();
        creditHistoryNewIdVo.setTenantId(record.getTenantId());
        creditHistoryNewIdVo.setCUserId(record.getId());
        creditHistoryNewIdVo.setNewUserId(user.getId());
        creditHistoryMapper.updateNewId(creditHistoryNewIdVo);

        // 10. base info
        CUserBaseVo userBaseVo = new CUserBaseVo();
        org.springframework.beans.BeanUtils.copyProperties(record, userBaseVo);
        userBaseVo.setNewId(user.getId());
        //userBaseVo.setCredit(user.getCredit());
        userBaseVo.setPoins(user.getScore());
        wxCUserBasicInfoMapper.updateNewId(userBaseVo);
    }

    @Override
    public void deleteById(Long id) {
        wxCUserBasicInfoMapper.deleteById(id);
    }

    @Override
    public long findCountBySex(WxCUserBasicInfoDto dto) {
        return wxCUserBasicInfoMapper.findCountBySex(dto);
    }

    @Override
    public long findCountByAge(WxCUserBasicInfoDto dto) {
        return wxCUserBasicInfoMapper.findCountByAge(dto);
    }

    @Override
    public long findCountByScore(WxCUserBasicInfoDto dto) {
        return wxCUserBasicInfoMapper.findCountByScore(dto);
    }

    @Override
    public int  exportDataCount(WxCUserBasicInfo basicInfo) {
        return wxCUserBasicInfoMapper.countVoList(basicInfo);
    }


    public void exportData(WxCUserBasicInfo  basicInfo, HttpServletRequest request, HttpServletResponse response) {
        List<WxCUserBasicInfoVo> list = wxCUserBasicInfoMapper.findVoList(basicInfo);
        List<WxTags> tagList = wxTagsMapper.findListAll();
        Map<Long, String> tagMap = tagList.stream().collect(Collectors.toMap(WxTags::getId, WxTags::getName));
        list.stream().filter(u->u.getTags()!=null).forEach(u->{
            List<Long> ids = JSONObject.parseArray(u.getTags(), Long.class);
            String tagNames = StringUtils.join(ids.stream().map(id->tagMap.get(id)).collect(Collectors.toList()),"/");
            u.setTagNames(tagNames);
        });
        excelService.exportExcel(list, null, "会员信息", WxCUserBasicInfoVo.class, "会员信息数据.xlsx", response, false);
    }

    public void exportTemplate(HttpServletRequest request, HttpServletResponse response, String tenantId) {
        List<WxCUserBasicInfoVo> list = new ArrayList<>();
        WxCUserBasicInfoVo u1 = new WxCUserBasicInfoVo();
        WxCUserBasicInfoVo u2 = new WxCUserBasicInfoVo();
        WxCUserBasicInfoVo u3 = new WxCUserBasicInfoVo();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");


        u1.setName("例子1");
        u1.setSex(0);
        u1.setPhone("13900010001");
        u1.setNickName("昵称");
        u1.setEducation("本科");
        u1.setCredit(10);
        u1.setAddress("地址");
        try {
            u1.setBirthdate(sdf.parse("2018-09-10"));
            u1.setCreateDate(sdf.parse("2018-08-10"));
            u1.setUpdateDate(sdf.parse("2018-08-10"));
        } catch (Exception e) {
            u1.setBirthdate(new Date());
            u1.setCreateDate(new Date());
            u1.setUpdateDate(new Date());
        }
        u1.setTagNames("附近住户");
        u1.setPoins(100);

        u2.setName("例子2");
        u2.setSex(1);
        u2.setPhone("13900010002");
        u2.setNickName("昵称");
        u2.setEducation("本科");
        u2.setCredit(20);
        u2.setAddress("地址");

        try {
            u2.setBirthdate(sdf.parse("2018-09-10"));
            u2.setCreateDate(sdf.parse("2018-08-10"));
            u2.setUpdateDate(sdf.parse("2018-08-10"));
        } catch (Exception e) {
            u2.setBirthdate(new Date());
            u2.setCreateDate(new Date());
            u2.setUpdateDate(new Date());
        }

        u2.setTagNames("男/附近住户");
        u2.setPoins(200);

        u3.setName("例子3");
        u3.setSex(2);
        u3.setPhone("13900010003");
        u3.setNickName("昵称");
        u3.setEducation("本科");
        u3.setCredit(30);
        u3.setAddress("地址");

        try {
            u3.setBirthdate(sdf.parse("2018-09-10"));
            u3.setCreateDate(sdf.parse("2018-08-10"));
            u3.setUpdateDate(sdf.parse("2018-08-10"));
        } catch (Exception e) {
            u3.setBirthdate(new Date());
            u3.setCreateDate(new Date());
            u3.setUpdateDate(new Date());
        }
        u3.setTagNames("女/附近住户");
        u3.setPoins(110);

        list.add(u1);
        list.add(u2);
        list.add(u3);

        excelService.exportExcel(list, null, "会员信息模板", WxCUserBasicInfoVo.class, "会员信息模板.xlsx", response, true);
    }


    public WxCUserBasicInfo InitUserBaseInfo(CUserBaseInfoT uBase, String tenantId) {
        if (StringUtils.isBlank(uBase.getPhone())) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        WxCUserBasicInfo userBase = new WxCUserBasicInfo();

        userBase.setTenantId(tenantId);
        userBase.setName(uBase.getName());
        if (uBase.getSex() == null) {
            userBase.setSex(0);
        } else {
            userBase.setSex(uBase.getSex());
        }

        userBase.setPhone(uBase.getPhone());
        userBase.setNickName(uBase.getNickName());
        userBase.setEducation(uBase.getEducation());
        if (uBase.getBirthdate() != null) {
            try {
                userBase.setBirthdate(sdf.parse(uBase.getBirthdate()));
            } catch (ParseException e) {
                logger.error("生日： " + e.getMessage());
            }
        }

        userBase.setAddress(uBase.getAddress());
        if (uBase.getUpdateDate() != null) {
            try {
                userBase.setUpdateDate(sdf.parse(uBase.getUpdateDate()));
            } catch (ParseException e) {
                logger.error("上次活跃时间： " + e.getMessage());
            }
        }
        if (uBase.getCreateDate() != null) {
            try {
                userBase.setCreateDate(sdf.parse(uBase.getCreateDate()));
            } catch (ParseException e) {
                logger.error("注册时间： " + e.getMessage());
            }
        }

        userBase.setTagNames(uBase.getTagNames());

        return userBase;
    }

    @Override
    public void importOneMem(String tenantId, String importKey, List<WxTags> tagList, CUserBaseInfoT uBase,MallUserInfo mallUserInfo) {
        final IdWorker idWorker = IdWorker.get();

        if (StringUtils.isBlank(uBase.getPhone())) {
            stringRedisTemplate.opsForHash().increment(importKey, "processCount", 1);
            logger.error("手机号为空", uBase.toString());
            return;
        }
        WxCUserBasicInfo userBase = InitUserBaseInfo(uBase, tenantId);
        if (userBase == null) {
            stringRedisTemplate.opsForHash().increment(importKey, "processCount", 1);
            logger.error("userBase为null", uBase.toString());
            return;
        }

        boolean bHaveCUser = false;

        // 成长值
        Integer points = null;
        if (StringUtils.isNotBlank(uBase.getPoins())) {
            try {
                points = Integer.valueOf(uBase.getPoins());
                userBase.setPoins(points);
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        }

        //积分
        Integer credit = null;
        if (StringUtils.isNotBlank(uBase.getCredit())) {
            try {
                credit = Integer.valueOf(uBase.getCredit());
                userBase.setCredit(credit);
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        }

        WxCUserBasicInfo oldUserBase = null;
        WxCUserBasicInfo userBaseQ = new WxCUserBasicInfo();
        userBaseQ.setTenantId(tenantId);
        userBaseQ.setPhone(userBase.getPhone());
        List<WxCUserBasicInfo> userBList = wxCUserBasicInfoMapper.selectList(new QueryWrapper(userBaseQ));
        if (userBList.size() > 0) {
            oldUserBase = userBList.get(0);
        }

        if (oldUserBase != null) {
            oldUserBase.setName(userBase.getName());
            oldUserBase.setSex(userBase.getSex());
            oldUserBase.setNickName(userBase.getNickName());
            oldUserBase.setEducation(userBase.getEducation());
            oldUserBase.setBirthdate(userBase.getBirthdate());
            oldUserBase.setAddress(userBase.getAddress());
            Date updateDate = oldUserBase.getUpdateDate() == null ? new Date() : oldUserBase.getUpdateDate();
            Date createDate = oldUserBase.getCreateDate() == null ? new Date() : oldUserBase.getCreateDate();
            oldUserBase.setUpdateDate(userBase.getUpdateDate() == null ? updateDate : userBase.getUpdateDate());
            oldUserBase.setCreateDate(userBase.getCreateDate() == null ? createDate : userBase.getCreateDate());
            if (oldUserBase.getStatus().equals(EnumCUserBasicInfoStatus.NORMAL.getCode())) {
                // 成长值
                if (points != null) {
                    oldUserBase.setPoins(points);
                }
                // 覆盖原积分
                if (credit != null) {
                    oldUserBase.setCredit(credit);
                }
            }
        } else {
            userBase.setId(idWorker.nextId());
            userBase.setUpdateDate(userBase.getUpdateDate() == null ? new Date() : userBase.getUpdateDate());
            userBase.setCreateDate(userBase.getCreateDate() == null ? new Date() : userBase.getCreateDate());
            //新增积分
            if(credit != null) {
                userBase.setCredit(credit);
            }
        }

        // update 昵称
        {
            // check c_user 是否存在
            WxCUser cUserQ = new WxCUser();
            cUserQ.setTenantId(tenantId);
            cUserQ.setPhone(userBase.getPhone());
            List<WxCUser> userList = wxCUserMapper.selectList(new QueryWrapper(cUserQ));
            if (userList.size() > 0) {
                WxCUser user = userList.get(0);
                if (user != null) {
                    //覆盖积分
                    if(credit != null) {
                        user.setCredit(credit);
                        wxCUserMapper.updateById(user);
                    }
                    bHaveCUser = true;
                    if (oldUserBase != null) {
                        if(oldUserBase != null) {
                            oldUserBase.setNickName(user.getNickName());
                        }
                        userBase.setId(user.getId());
                        userBase.setNickName(user.getNickName());
                    } else {
                        userBase.setNickName(user.getNickName());
                    }
                }
            }
        }


        if (oldUserBase != null) {
            logger.info("update user base: " + oldUserBase.getId());
            wxCUserBasicInfoMapper.updateById(oldUserBase);
        } else {
            logger.info("insert user base: " + userBase.getId());
            try {
                wxCUserBasicInfoMapper.insert(userBase);
            } catch (Exception e) {
                stringRedisTemplate.opsForHash().increment(importKey, "processCount", 1);
                logger.error(e.getMessage());
                return;
            }
        }
        // update tags
        try {
            if (StringUtils.isNotBlank(userBase.getTagNames())) {
                // get tag ids
                String tagNames = userBase.getTagNames();
                List<Long> tagIdList = new ArrayList<>();
                for (String tagName : tagNames.split("/")) {
                    for(WxTags tag: tagList) {
                        if(tagName.equals(tag.getName())) {
                            tagIdList.add(Long.valueOf(tag.getId()));
                            break;
                        }
                    }
                }

                if (oldUserBase != null){
                    wxCUserTagsService.assignTags(tagIdList,oldUserBase);
                }else{
                    wxCUserTagsService.assignTags(tagIdList,userBase);
                }
            }

            //触发自动打标签, 晚上会自动打标签，所以去掉导入打标签
            /*
            if (oldUserBase != null) {
                wxCUserTagsService.triggerAssignTags(EnumAssignTagsTrigger.ASSIGN_TAGS_TRIGGER_IMPORT,oldUserBase);
            }
            else{
                wxCUserTagsService.triggerAssignTags(EnumAssignTagsTrigger.ASSIGN_TAGS_TRIGGER_IMPORT,userBase);
            }
            */

            // 成长值
            if (points != null) {
                if (oldUserBase != null) {
                    wxScoreRulesService.addScore2(EnumScoreType.MEM_IMPORT, oldUserBase, bHaveCUser);
                } else {
                    wxScoreRulesService.addScore2(EnumScoreType.MEM_IMPORT, userBase, bHaveCUser);
                }
            }
            //积分处理逻辑：覆盖原积分 记录历史
            if (credit != null) {
                WxCreditHistory wxCreditHistory = new WxCreditHistory();
                wxCreditHistory.setTenantId(tenantId);
                wxCreditHistory.setCreateDate(new Date());
                if (mallUserInfo != null) {
                    wxCreditHistory.setOperatorId(mallUserInfo.getId());
                    wxCreditHistory.setOperatorType(EnumUserType.MALLUSER.getCode());
                }
                wxCreditHistory.setCreditType(EnumScoreType.MEM_IMPORT.getCode());
                if (oldUserBase != null) {
                    wxCreditHistory.setCUserId(oldUserBase.getId());
                } else {
                    wxCreditHistory.setCUserId(userBase.getId());
                }
                wxCreditHistory.setCreditAmount(credit);
                wxCreditHistory.setCreditNum(credit);
                wxCreditHistoryService.saveOrUpdate(wxCreditHistory);
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            logger.error("打标签+成长值失败--继续导入");
        }

        //记数
        stringRedisTemplate.opsForHash().increment(importKey,"processCount",1);
        stringRedisTemplate.expire(importKey,10, TimeUnit.SECONDS);
    }

    @Override
    public long findCount(WxCUserBasicInfoDto dto) {
        return wxCUserBasicInfoMapper.findCount(dto);
    }

    @Override
    public List<UserCountVo> findCountHistory(WxCUserBasicInfoDto dto) {
        return wxCUserBasicInfoMapper.findCountHistory(dto);
    }

    @Override
    public void exportCarPayData(WxCarPayRecord record, HttpServletRequest request, HttpServletResponse response) {
        List<WxCarPayRecord> list = wxCarPayRecordMapper.findCarPayList(record);
        String sheetName = (record.getIsPay()!=null && 1==record.getIsPay())?"线上缴费车辆列表":"进出车辆列表";
        excelService.exportExcel(list, null, sheetName, WxCarPayRecord.class, sheetName + ".xlsx", response, false);
    }

    @Override
    public long findCountByFilter(WxCUserBasicInfoDto dto) {
        return wxCUserBasicInfoMapper.findCount(dto);
    }

    @Override
    public long findGrowUserCount(WxCUserBasicInfoDto dto) {
        return wxCUserBasicInfoMapper.findGrowUserCount(dto);
    }

    @Override
    public long findImportUserCount(WxCUserBasicInfoDto dto) {
        return wxCUserBasicInfoMapper.findImportUserCount(dto);
    }

    @Override
    public ResultData updateStatus(WxCUserBasicInfo wxCUserBasicInfo) {
        wxCUserBasicInfo.setUpdateDate(new Date());
        wxCUserBasicInfoMapper.updateById(wxCUserBasicInfo);
        return new ResultData();
    }
}

