package com.bonus.canteen.core.pay.common.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.canteen.core.order.utils.LeNumUtil;
import com.bonus.canteen.core.order.utils.LeOrderUtil;
import com.bonus.canteen.core.pay.common.constants.PayStateEnum;
import com.bonus.canteen.core.pay.common.mapper.TradeRecordChannelMapper;
import com.bonus.canteen.core.pay.common.model.TradeChannel;
import com.bonus.canteen.core.pay.common.service.TradeChannelService;
import com.bonus.canteen.core.pay.common.vo.TradeChannelVO;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

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

@Service
public class TradeChannelServiceImpl extends ServiceImpl<TradeRecordChannelMapper, TradeChannel> implements TradeChannelService {
    private static final Logger log = LoggerFactory.getLogger(TradeChannelServiceImpl.class);
    private final LeNumUtil leNumUtil;

    public TradeChannelServiceImpl(LeNumUtil leNumUtil) {
        this.leNumUtil = leNumUtil;
    }

    @Override
    public void updateTradeRecordChannelState(Long channelId, Integer tradeState, String tradeResult, String outTradeNo, BigDecimal realAmount, JsonNode param, LocalDateTime tradeTime) {
        log.info("[渠道支付]更新渠道明细 开始");
        List<LocalDateTime> createTimeRange = LeOrderUtil.queryCreateTimeRange(channelId);
        ((TradeRecordChannelMapper) this.baseMapper).update(null,Wrappers.<TradeChannel>lambdaUpdate()
                .set(TradeChannel::getTradeState, tradeState)
                .set(TradeChannel::getTradeResult, tradeResult)
                .set(CharSequenceUtil.isNotEmpty(outTradeNo), TradeChannel::getOutTradeNo, outTradeNo)
                .set(realAmount != null && PayStateEnum.isPaidState(tradeState), TradeChannel::getAmount, realAmount)
                .set(param != null, TradeChannel::getParam, param)
                .set(tradeTime != null, TradeChannel::getTradeTime, tradeTime)
                .eq(TradeChannel::getTradeChannelId, channelId)
                .between(TradeChannel::getCreateTime, createTimeRange.get(0), createTimeRange.get(1)));
        log.info("[渠道支付]更新渠道明细 开始");
    }

    @Override
    public void insert(TradeChannel tradeChannel) {
        log.info("[渠道支付]插入渠道明细 开始 {}", tradeChannel.getTradeTime());
        ((TradeRecordChannelMapper) this.baseMapper).insert(tradeChannel);
        log.info("[渠道支付]插入渠道明细 结束");
    }

    @Override
    public List<TradeChannelVO> listChannelDetailByTradeId(Long tradeId) {
        return (List)(!LeNumUtil.isValidId(tradeId) ? CollUtil.newArrayList(new TradeChannelVO[0]) : this.listChannelDetailByTradeIds(CollUtil.toList(new Long[]{tradeId})));
    }

    @Override
    public List<TradeChannelVO> listChannelDetailByTradeIds(List<Long> tradeIds) {
        if (CollUtil.isEmpty(tradeIds)) {
            return CollUtil.newArrayList(new TradeChannelVO[0]);
        } else {
            List<LocalDateTime> createTimeRange = LeOrderUtil.queryCreateTimeRange(tradeIds);
            return ((TradeRecordChannelMapper)this.baseMapper).selectList(Wrappers.lambdaQuery(TradeChannel.class)
                    .in(TradeChannel::getTradeId, tradeIds)
                    .between(TradeChannel::getCreateTime, createTimeRange.get(0), createTimeRange.get(1)))
                    .stream().map(TradeChannelVO::of)
                    .collect(Collectors.toList());
        }
    }

    public TradeChannel getByTradeChannelId(Long tradeChannelId) {
        if (!LeNumUtil.isValidId(tradeChannelId)) {
            return null;
        } else {
            List<LocalDateTime> createTimeRange = LeOrderUtil.queryCreateTimeRange(tradeChannelId);
            return this.baseMapper.selectOne(Wrappers
                    .lambdaQuery(TradeChannel.class).eq(TradeChannel::getTradeChannelId, tradeChannelId)
                    .between(TradeChannel::getCreateTime, createTimeRange.get(0), createTimeRange.get(1)));
        }
    }

    public void updateTradeIdForRepair(Long channelId, Long newTradeId) {
        List<LocalDateTime> createTimeRange = LeOrderUtil.queryCreateTimeRange(channelId);
        ((TradeRecordChannelMapper)this.baseMapper).update(null, Wrappers
                .lambdaUpdate(TradeChannel.class).set(TradeChannel::getTradeId, newTradeId)
                .eq(TradeChannel::getTradeChannelId, channelId).between(TradeChannel::getCreateTime, createTimeRange.get(0)
                , createTimeRange.get(1)));
    }

    public void updateRefundAmount(Long channelId, BigDecimal amount) {
        if (LeNumUtil.isValidId(channelId)) {
            List<LocalDateTime> createTimeRange = LeOrderUtil.queryCreateTimeRange(channelId);
            this.baseMapper.update(null, Wrappers
                    .lambdaUpdate(TradeChannel.class).set(TradeChannel::getRefundAmount, amount)
                    .eq(TradeChannel::getTradeChannelId, channelId)
                    .between(TradeChannel::getCreateTime, createTimeRange.get(0), createTimeRange.get(1)));
        }
    }
}
