package cn.iocoder.yudao.module.member.dal.mysql.card;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.member.controller.admin.card.vo.CardPageReqVO;
import cn.iocoder.yudao.module.member.controller.app.card.vo.AppCardMonthVO;
import cn.iocoder.yudao.module.member.controller.app.card.vo.AppCardPageReqVO;
import cn.iocoder.yudao.module.member.controller.app.card.vo.FaceVo;
import cn.iocoder.yudao.module.member.dal.dataobject.billing.BillingDO;
import cn.iocoder.yudao.module.member.dal.dataobject.card.CardDO;
import cn.iocoder.yudao.module.member.enums.BillingStatusEnum;
import cn.iocoder.yudao.module.member.enums.CostTypeEnum;
import cn.iocoder.yudao.module.member.util.MemberConstants;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 余额变动明细 Mapper
 *
 * @author 开发账号
 */
@Mapper
public interface CardMapper extends BaseMapperX<CardDO> {

    default PageResult<CardDO> selectPage(CardPageReqVO reqVO) {
        return selectPage(reqVO, new LambdaQueryWrapperX<CardDO>()
                .eqIfPresent(CardDO::getUserId, reqVO.getUserId())
                .eqIfPresent(CardDO::getMoney, reqVO.getMoney())
                .eqIfPresent(CardDO::getFlag, reqVO.getFlag())
                .eqIfPresent(CardDO::getChangeMoney, reqVO.getChangeMoney())
                .betweenIfPresent(CardDO::getCreateTime, reqVO.getCreateTime())
                .eqIfPresent(CardDO::getCarteenId,reqVO.getCarteenId())
                .orderByDesc(CardDO::getId));
    }

    default PageResult<CardDO> selectPage(AppCardPageReqVO reqVO) {
        return selectPage(reqVO, new LambdaQueryWrapperX<CardDO>()
                .eqIfPresent(CardDO::getUserId, reqVO.getUserId())
                .eqIfPresent(CardDO::getMoney, reqVO.getMoney())
                .eqIfPresent(CardDO::getFlag, reqVO.getFlag())
                .eqIfPresent(CardDO::getChangeMoney, reqVO.getChangeMoney())
                .betweenIfPresent(CardDO::getCreateTime, reqVO.getCreateTime())
                .eqIfPresent(CardDO::getCarteenId,reqVO.getCarteenId())
                .orderByDesc(CardDO::getId));
    }

    @Select("select IFNULL(sum(change_money),0) as money,count(*) as count FROM member_card where user_id = #{userId} and flag = #{flag} and  create_time BETWEEN #{startTime} and #{endTime}")
    AppCardMonthVO selectMonth(@Param("userId") Long userId,@Param("flag") String flag, @Param("startTime") LocalDateTime startTime, @Param("endTime")LocalDateTime endTime);
    @Select("select SUM(change_money) from member_card where user_id= #{userId} and flag= #{flag} and type= '5'")
    BigDecimal selectAddMoney(@Param("userId") Long userId,@Param("flag") String flag);
    @Select("select SUM(change_money) from member_card where user_id= #{userId} and flag= #{flag}")
    BigDecimal selectReduceMoney(@Param("userId") Long userId,@Param("flag") String flag);
    @Select("select sum(change_money) from member_card where user_id= #{userId} and type= '1'")
    BigDecimal selectWxMoney(@Param("userId") Long userId);

    List<CardDO> selectMoneyList(List<Long> list);

    FaceVo getFaceData(String faceId);

    default BigDecimal getMoneyByUsr(Long userId){
        CardDO lastCardDO = selectOne(Wrappers.<CardDO>lambdaQuery().eq(CardDO::getUserId, userId)
                .orderByDesc(CardDO::getCreateTime)
                .orderByDesc(CardDO::getId)
                .last(MemberConstants.LIMIT_ONE));
        if (lastCardDO == null || lastCardDO.getMoney() == null) {
            return BigDecimal.ZERO;
        }
        return lastCardDO.getMoney();
    }
    default List<CardDO> getMoneyByUserIds(Collection<Long> userIds , String flag, String type,Integer var,Integer var2,Long groupId){
        List<CardDO> cardDOS = selectList(new LambdaQueryWrapperX<CardDO>()
                .eq(CardDO::getFlag, flag)
                .eq(CardDO::getType, type)
                .eq(CardDO::getBillingExist, var)
                .eqIfPresent(CardDO::getGroupId,groupId)
                .in(CardDO::getUserId, userIds));
        DateTime date = DateUtil.date();
        int year = date.year();
        cardDOS=cardDOS.stream().filter(f-> f.getCreateTime().getYear()==year).collect(Collectors.toList());
        if(var2!=null){
            return cardDOS.stream().filter(f-> f.getCreateTime().getMonth().getValue()==var2).collect(Collectors.toList());
        }else{
            int i = date.monthBaseOne();
            return cardDOS.stream().filter(f-> f.getCreateTime().getMonth().getValue()!=i).collect(Collectors.toList());
        }
    }
    default BigDecimal getTotalMoneyByuserIds(Collection<Long> userIds, String flag, String type,Integer var,Long groupId) {
        List<CardDO> cardDOS = selectList(new LambdaQueryWrapperX<CardDO>()
                .eq(CardDO::getFlag, flag)
                .eq(CardDO::getType, type)
                .eqIfPresent(CardDO::getGroupId,groupId)
                .eq(CardDO::getBillingExist, BillingStatusEnum.BILLING_INVOICING_REJECTION.getCode())
                .in(CardDO::getUserId, userIds));
        DateTime date = DateUtil.date();
        int year = date.year();
        cardDOS=cardDOS.stream().filter(f-> f.getCreateTime().getYear()==year).collect(Collectors.toList());
        if(var!=null){
            cardDOS=cardDOS.stream().filter(f-> f.getCreateTime().getMonth().getValue()==var).collect(Collectors.toList());
        }else{
            int i = date.monthBaseOne();
            cardDOS=cardDOS.stream().filter(f-> f.getCreateTime().getMonth().getValue()!=i).collect(Collectors.toList());
        }
        return   cardDOS.stream()
                .map(CardDO::getChangeMoney)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    default BigDecimal getTotalMoneyByGroup(List<Long> userIds,Integer year,Integer month) {
        String mon =  month<10?"0"+month:month.toString();
        List<CardDO> cardDOS = selectList(new LambdaQueryWrapper<CardDO>()
                .eq(CardDO::getFlag,  CardDO.ADD)
                .eq(CardDO::getType,  CostTypeEnum.ADMIN_PAY.getCode())
                .in(CardDO::getUserId, userIds)
                .apply("DATE_FORMAT(create_time, '%Y-%m')= {0}",year+"-"+mon));
        return   cardDOS.stream()
                .map(CardDO::getChangeMoney)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    int udpateEXit(@Param("orderIds") Collection<Long>  orderIds,@Param("exit") Integer exit,@Param("num")String num);
}