package com.fzm.mall.server.front.asset.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fzm.mall.server.front.asset.mapper.*;
import com.fzm.mall.server.front.asset.model.*;
import com.fzm.mall.server.front.asset.model.dto.UserAssetTransferSaveDTO;
import com.fzm.mall.server.front.asset.model.dto.UserAssetTransferUpdateDTO;
import com.fzm.mall.server.front.asset.model.vo.GoodsTransVO;
import com.fzm.mall.server.front.asset.model.vo.UserAssetTransferVO;
import com.fzm.mall.server.front.asset.service.ITranService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.mall.server.front.goods.service.ICategoryService;
import com.fzm.mall.server.front.goods.mapper.GoodSkuMapper;
import com.fzm.mall.server.front.user.mapper.UserMapper;
import com.fzm.mall.server.front.user.model.User;
import com.fzm.mall.server.front.util.CopyUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author fzm
 * @since 2021-09-07
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TranServiceImpl extends ServiceImpl<TranMapper, Tran> implements ITranService {
    private final TranMapper tranMapper;
    private final UserAssetTransferLogMapper transferLogMapper;
    private final UserAssetMapper userAssetMapper;
    private final UserAssetRecordMapper userAssetRecordMapper;
    private final UserMapper userMapper;
    private final TranOrderMapper tranOrderMapper;
    private final GoodSkuMapper goodSkuMapper;



    @Override
    public IPage<GoodsTransVO> page(Page<GoodsTransVO> page, String keyword) {
        IPage<GoodsTransVO> list = tranMapper.list(page, keyword,1);
        return list;
    }
    @Override
    public IPage<GoodsTransVO> pageSerach(Page<GoodsTransVO> page, String keyword,String goodsIds,String price,String sale) {
        IPage<GoodsTransVO> list = tranMapper.pageSerach(page, keyword,1,goodsIds,price,sale);
        return list;
    }

    @Override
    public Tran getByTranId(String tranId) {
        QueryWrapper<Tran> q = new QueryWrapper<>();
        q.eq("tran_id",tranId);
        return getOne(q);
    }

    @Override
    public Tran getByTranIdForUpdate(Integer id) {
        return tranMapper.getByTranIdForUpdate(id);
    }

    @Override
    public int delStock(Integer id, Integer number) {
        return tranMapper.delStock(id,number);
    }

    @Override
    public Tran getByUidAndOid(String uid, String tranId) {
        QueryWrapper<Tran> q = new QueryWrapper<>();
        q.eq("uid",uid);
        q.eq("tran_id",tranId);
        return getOne(q);
    }

    @Override
    public void save(UserAssetTransferSaveDTO saveDTO) {
        Tran transfer = CopyUtil.to(saveDTO, Tran.class);
        checkTransferNum(transfer);

        transfer.init();
        tranMapper.insert(transfer);
    }

    /**
     * 校验转让数量是否小于等于用户资产
     *
     * @param transfer
     */
    private void checkTransferNum(Tran transfer) {
        QueryWrapper<UserAsset> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("uid", transfer.getUid())
                .eq("coin", transfer.getCoin());
        UserAsset userAsset = userAssetMapper.selectOne(queryWrapper);
        boolean numError = userAsset.getAmount().compareTo(new BigDecimal(transfer.getNumber())) == -1;
        if (userAsset == null || numError) {
            throw new RuntimeException("user asset not enough, transferNum is invalid");
        }
        /**
         * 从用户资产中扣除
         */
        BigDecimal amount = userAsset.getAmount().subtract(new BigDecimal(transfer.getNumber()));
        userAsset.setAmount(amount);
        UpdateWrapper<UserAsset> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("uid", userAsset.getUid())
                .eq("coin", userAsset.getCoin())
                .eq("update_time", userAsset.getUpdateTime());
        int update = userAssetMapper.update(userAsset, updateWrapper);
        if (update == 0) {
            throw new RuntimeException("update fail");
        }
        /**
         * 生成资产变更记录
         */
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("uid", transfer.getUid()));
        UserAssetRecord record = new UserAssetRecord();
        record.init(transfer.getUid(), transfer.getCoin(), 17, new BigDecimal(transfer.getNumber()), 2,
                user.getAddress(), null, "发布转让扣除用户资产");
        userAssetRecordMapper.insert(record);
    }

    @Override
    public Long update(UserAssetTransferUpdateDTO updateDTO) {
        Tran transfer = CopyUtil.to(updateDTO, Tran.class);
        Tran oldTransfer = checkStatus(transfer.getTranId());

        UpdateWrapper<Tran> wrapper = new UpdateWrapper<>();
        wrapper.eq("tran_id", transfer.getTranId())
                .eq("update_time", transfer.getUpdateTime());
        int update = tranMapper.update(transfer, wrapper);
        if (update == 0) {
            throw new RuntimeException("update fail");
        }

        //添加操作日志
        addTransferLog(transfer.getTranId(), oldTransfer.getPrice(), transfer.getPrice(), UserAssetTransferLog.TRANSFER_LOG_TYPE_UPDATE_PRICE);
        return transfer.getUpdateTime();
    }

    private Tran checkStatus(String transferId) {
        QueryWrapper<Tran> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tran_id", transferId);
        Tran transfer = tranMapper.selectOne(queryWrapper);
        if (transfer == null || Tran.TRANSFER_STATUS_CANCLED.equals(transfer.getStatus())) {
            throw new RuntimeException("status error, update fail");
        }
        return transfer;
    }

    @Override
    public void cancle(String uid, String transferId) {
        checkBeforeCancle(transferId);

        Tran transfer = readById(transferId);
        if (transfer == null || Tran.TRANSFER_STATUS_CANCLED.equals(transfer.getStatus())) {
            throw new RuntimeException("update fail");
        }
        /**
         * 资产退还
         */
        QueryWrapper<UserAsset> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("uid", uid)
                .eq("coin", transfer.getCoin());
        UserAsset userAsset = userAssetMapper.selectOne(queryWrapper);

        BigDecimal amount = userAsset.getAmount().add(new BigDecimal(transfer.getNumber()));
        userAsset.setAmount(amount);
        UpdateWrapper<UserAsset> updateAssetWrapper = new UpdateWrapper<>();
        updateAssetWrapper.eq("uid", uid)
                .eq("coin", userAsset.getCoin())
                .eq("update_time", userAsset.getUpdateTime());
        int update = userAssetMapper.update(userAsset, updateAssetWrapper);
        if (update == 0) {
            throw new RuntimeException("update fail");
        }

        transfer.setStatus(Tran.TRANSFER_STATUS_CANCLED);
        UpdateWrapper<Tran> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("tran_id", transferId)
                .eq("uid", uid);
        int tUpdate = tranMapper.update(transfer, updateWrapper);
        if (tUpdate == 0) {
            throw new RuntimeException("update fail");
        }

        //添加操作日志
        addTransferLog(transferId, null, null, UserAssetTransferLog.TRANSFER_LOG_TYPE_CANCLE);
    }

    private void checkBeforeCancle(String transferId) {
        QueryWrapper<TranOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tran_id", transferId).eq("status", TranOrder.TRAN_ORDER_STATUS_SUCCESS);
        List<TranOrder> tranOrderList = tranOrderMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(tranOrderList)) {
            throw new RuntimeException("record_exist");
        }
    }

    @Override
    public UserAssetTransferVO read(String transferId) {
        UserAssetTransferVO transfer = tranMapper.read(transferId);
        transfer.listProval(goodSkuMapper);
        transfer.listRecord(tranOrderMapper);
        return transfer;
    }

    @Override
    public IPage<UserAssetTransferVO> page(Page<UserAssetTransferVO> page, String uid, String keyword) {
        List<UserAssetTransferVO> list = tranMapper.listByUid(uid, keyword, Tran.TRANSFER_STATUS_EFFECTIVE);
        return getPageResult(list, page);
    }

    private Tran readById(String transferId) {
        QueryWrapper<Tran> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tran_id", transferId);
        return tranMapper.selectOne(queryWrapper);
    }

    private IPage<UserAssetTransferVO> getPageResult(List<UserAssetTransferVO> list, Page<UserAssetTransferVO> page) {

        IPage<UserAssetTransferVO> result = new Page<>(page.getCurrent(), page.getSize(), list.size());

        int currentPage = (int) result.getCurrent();
        int pageSize = (int) result.getSize();
        int total = list.size();
        int pages = (int) result.getPages();
        //当前第几页数据
        currentPage = pages < currentPage ? pages : currentPage;
        //起始索引
        int fromIndex = pageSize * (currentPage - 1) < 0 ? 0 : pageSize * (currentPage - 1);
        //结束索引
        int toIndex = pageSize * currentPage > total ? total : pageSize * currentPage;

        list = list.subList(fromIndex, toIndex);
        list.forEach(item -> item.listRecord(tranOrderMapper));
        result.setRecords(list);
        return result;
    }

    private void addTransferLog(String transferId, BigDecimal oldPrice, BigDecimal newPrice, Integer type) {
        UserAssetTransferLog transferLog = new UserAssetTransferLog();
        transferLog.init(transferId, oldPrice, newPrice, type);

        transferLogMapper.insert(transferLog);
    }
}
