package com.apobates.forum.member;

import com.apobates.forum.event.elderly.ForumActionEnum;
import com.apobates.forum.member.MemberProfileBean.MemberProfileBuilder;
import com.apobates.forum.member.entity.ForumScoreRole;
import com.apobates.forum.member.entity.MemberGroupEnum;
import com.apobates.forum.member.entity.MemberLevel;
import com.apobates.forum.member.entity.MemberRoleEnum;
import com.apobates.forum.utils.lang.CommonDoubleBean;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 会员个人信息处理类
 *
 * @author xiaofanku
 * @since 20200517
 */
public class MemberProfile {
    private final List<MemberProfileBuilder> data;
    private final static Logger logger = LoggerFactory.getLogger(MemberProfile.class);
    
    private MemberProfile(List<MemberProfileBuilder> data) {
        this.data = List.copyOf(data);
    }
    
    public static MemberProfile init(long memberId, String memberNickname, MemberGroupEnum memberGroup, MemberRoleEnum memberRole, String signature) {
        return new MemberProfile(
                Arrays.asList(
                        new MemberProfileBuilder(
                                memberId,
                                memberNickname,
                                memberGroup.getTitle(),
                                memberRole.getTitle(),
                                MemberBaseProfile.getStyle(memberGroup, memberRole),
                                signature)));
    }
    
    public static MemberProfile init(List<MemberBaseProfile> beans) {
        Function<MemberBaseProfile, MemberProfileBuilder> action = (MemberBaseProfile mbp)->{
            return new MemberProfileBuilder(mbp.getId(), mbp.getNickname(), mbp.getGroupName(), mbp.getRoleName(), mbp.getLabel(), mbp.getSignature());
        };
        List<MemberProfileBuilder> data = beans.stream().map(action).collect(Collectors.toList());
        return new MemberProfile(data);
    }
    //多个中改一个呢?
    
    /**
     * 计算某会员的积分
     *
     * @param memberId 会员ID
     * @param statsdata 操作记录的统计
     * @param scoreRoleSet 积分规则定义
     * @return
     */
    public Optional<MemberProfile> calcMemberScore(final long memberId, final Map<ForumActionEnum, Long> statsdata, final List<ForumScoreRole> scoreRoleSet) {
        if (!isContinue()) {
            logger.info("[MP][calcMemberScore]缺少必要的属性: data");
            return Optional.empty();
        }
        Function<MemberProfileBuilder, MemberProfileBuilder> action = mpb ->{
            if (mpb.getId() == memberId) {
                return fill(mpb, statsdata, scoreRoleSet).orElse(null);
            }
            return mpb;
        };
        List<MemberProfileBuilder> rs = data.stream().map(action).filter(Objects::nonNull).collect(Collectors.toList());
        return Optional.of(new MemberProfile(rs));
    }
    
    /**
     * 计算会员的积分
     *
     * @param rawdata 操作记录的统计
     * @param scoreRoleSet 积分规则定义
     * @return
     */
    public Optional<MemberProfile> calcMemberScore(final Map<Long, Map<ForumActionEnum, Long>> rawdata, final List<ForumScoreRole> scoreRoleSet) {
        if (!isContinue()) {
            logger.info("[MP][calcMemberScore][Map]缺少必要的属性: data");
            return Optional.empty();
        }
        Function<MemberProfileBuilder, MemberProfileBuilder> action = mpb ->{
             if (rawdata.containsKey(mpb.getId())) {
                return fill(mpb, rawdata.get(mpb.getId()), scoreRoleSet).orElse(null);
             }
            return mpb;
        };
        List<MemberProfileBuilder> rs = data.stream().map(action).filter(Objects::nonNull).collect(Collectors.toList());
        return Optional.of(new MemberProfile(rs));
    }
    
    private Optional<MemberProfileBuilder> fill(MemberProfileBuilder source, Map<ForumActionEnum, Long> statsdata, List<ForumScoreRole> scoreRoleSet) {
        if (source == null) {
            return Optional.empty();
        }
        MemberProfileBuilder newMpb = new MemberProfileBuilder(source.getId(), source.getNickname(), source.getGroupName(), source.getRoleName(), source.getLabel(), source.getSignature());
        double sv = getMemberScore(statsdata, scoreRoleSet);
        //logger.info("[MP][bean]mid: " + newMpb.getId() + ", score: " + sv);
        newMpb.setScore(sv);
        newMpb.setReplies(statsdata.getOrDefault(ForumActionEnum.POSTS_REPLY, 0L));
        newMpb.setThreads(statsdata.getOrDefault(ForumActionEnum.TOPIC_PUBLISH, 0L));
        newMpb.setLevel(source.getLevel(), source.getLevelNo());
        return Optional.of(newMpb);
    }
    
    /**
     * 计算会员的等级
     *
     * @param levelDefines
     * @return
     */
    public Optional<MemberProfile> calcMemberLevel(List<CommonDoubleBean> levelDefines) {
        if (!isContinue()) {
            logger.info("[MP][calcMemberLevel][List]缺少必要的属性: data");
            return Optional.empty();
        }
        Consumer<MemberProfileBuilder> action = mpb ->{
            MemberLevel l = queryLevel(mpb.getScore(), levelDefines);
            mpb.setLevel(l.getNames(), l.getId());
        };
        List<MemberProfileBuilder> rs = data.stream().peek(action).collect(Collectors.toList());
        return Optional.of(new MemberProfile(rs));
    }
    
    public boolean isContinue() {
        return data != null && !data.isEmpty();
    }
    
    public Optional<MemberProfileBean> toResultBean() {
        if (!isContinue()) {
            logger.info("[MP][toResultBean]缺少必要的属性: data");
            return Optional.empty();
        }
        MemberProfileBean rs = data.stream().filter(Objects::nonNull).findFirst().map(mb -> mb.build()).orElseGet(null);
        return Optional.ofNullable(rs);
    }
    
    public Optional<MemberProfileBean> toProfileBean() {
        if (!isContinue()) {
            return Optional.empty();
        }
        MemberProfileBean rs = data.stream().filter(Objects::nonNull).findFirst().map(mb -> mb.build()).orElseGet(null);
        return Optional.of(rs);
    }
    
    public List<MemberProfileBean> toBeanList() {
        if (!isContinue()) {
            logger.info("[MP][toBeanList]缺少必要的属性: data");
            return Collections.emptyList();
        }
        return data.stream().filter(Objects::nonNull).map(mb -> mb.build()).collect(Collectors.toList());
    }
    
    /**
     * 计算积分的方法
     *
     * @param actionStatsData 会员操作统计汇总
     * @param scoreroles 积分规则
     * @return
     */
    public static double getMemberScore(final Map<ForumActionEnum, Long> actionStatsData, final List<ForumScoreRole> scoreroles) {
        BiFunction<Long, ForumScoreRole, Double> accumulator = (operateSize, fsr)->{
            if(operateSize.compareTo(0L)==1 && null != fsr){
                return operateSize / fsr.getDegree() * fsr.getScore();
            }
            return 0.0;
        };
        //mapToDouble
        return scoreroles.stream().map(fsr -> accumulator.apply(actionStatsData.getOrDefault(fsr.getAction(), 0L), fsr)).mapToDouble(Double::doubleValue).sum();
    }
    
    /**
     *
     *
     * @param scoreValue 得分值
     * @param levelScoreDefined 等级定义
     * @return
     */
    public static MemberLevel queryLevel(double scoreValue, List<CommonDoubleBean> levelScoreDefined) {
        if(scoreValue <= 0 || null == levelScoreDefined || levelScoreDefined.isEmpty()){
            return MemberLevel.empty();
        }
        String levelName = CommonDoubleBean.empty().getFormatter(levelScoreDefined).format(scoreValue);
        //从定义中找到是几级
        Optional<CommonDoubleBean> result = levelScoreDefined.stream().filter(cdb -> cdb.getTitle().equals(levelName)).findFirst();
        MemberLevel data = new MemberLevel();
        data.setId(result.orElse(CommonDoubleBean.empty()).getId());
        data.setNames(levelName);
        data.setScore(scoreValue);
        data.setStatus(true);
        return data;
    }
}