package com.fjhx.service.water.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.base.Condition;
import com.fjhx.base.StorageBaseEntity;
import com.fjhx.constants.StatusConstant;
import com.fjhx.entity.water.WaterTransfer;
import com.fjhx.entity.water.WaterTransferDetails;
import com.fjhx.mapper.water.WaterTransferMapper;
import com.fjhx.params.water.WaterTransferVo;
import com.fjhx.service.material.MaterialService;
import com.fjhx.service.water.WaterTransferDetailsService;
import com.fjhx.service.water.WaterTransferService;
import com.fjhx.utils.UserClientUtil;
import org.springblade.core.secure.utils.AuthUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 转仓 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-10-28
 */
@Service
public class WaterTransferServiceImpl extends ServiceImpl<WaterTransferMapper, WaterTransfer> implements WaterTransferService {

    @Autowired
    private WaterTransferDetailsService waterTransferDetailsService;

    @Autowired
    private MaterialService materialService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(List<WaterTransferVo> waterTransferVoList) {

        List<WaterTransferDetails> waterTransferDetailsList = new ArrayList<>();

        for (WaterTransferVo waterTransferVo : waterTransferVoList) {
            List<WaterTransferDetails> itemDetailsList = waterTransferVo.getWaterTransferDetailsList();

            waterTransferVo.setNumber(itemDetailsList.size());
            waterTransferVo.setQuantity(itemDetailsList.stream()
                    .map(WaterTransferDetails::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add));
            waterTransferVo.setStatus(StatusConstant.NO);
            save(waterTransferVo);

            for (WaterTransferDetails waterTransferDetails : itemDetailsList) {
                waterTransferDetails.setWaterTransferId(waterTransferVo.getId());
                waterTransferDetails.setReceiveId(waterTransferVo.getReceiveId());
                waterTransferDetails.setMaterialId(waterTransferVo.getMaterialId());
                waterTransferDetails.setOldQuantity(waterTransferDetails.getQuantity());
                waterTransferDetails.setStatus(StatusConstant.NO);
            }
            waterTransferDetailsList.addAll(itemDetailsList);
        }

        waterTransferDetailsService.saveBatch(waterTransferDetailsList);
    }

    @Override
    public List<Map<String, Object>> toBeReviewedList() {

        List<Map<String, Object>> list = listMaps(Wrappers.<WaterTransfer>lambdaQuery()
                .eq(WaterTransfer::getStatus, StatusConstant.NO));

        if (list.size() == 0) {
            return list;
        }

        Set<Long> userIdList = new HashSet<>();

        list.forEach(item -> {
            userIdList.add(Convert.toLong(item.get("createUser")));
            userIdList.add(Convert.toLong(item.get("receiveId")));
        });

        Map<Long, String> userNameMap = UserClientUtil.getUserNameMap(userIdList);

        list.forEach(item -> {
            item.put("createUserName", userNameMap.get(Convert.toLong(item.get("createUser"))));
            item.put("receiveUserName", userNameMap.get(Convert.toLong(item.get("receiveId"))));
        });

        return list;
    }

    @Override
    public Map<String, Object> details(Long id) {
        Map<String, Object> map = getMap(StorageBaseEntity::getId, id);
        map.put("receiveUserName", UserClientUtil.getUserName(Convert.toLong(map.get("receiveId"))));
        map.put("materialName", materialService.getById(Convert.toLong(map.get("materialId"))).getName());

        List<WaterTransferDetails> list = waterTransferDetailsService.list(WaterTransferDetails::getWaterTransferId, id);
        map.put("list", list);

        return map;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Long id) {
        removeById(id);
        waterTransferDetailsService.remove(WaterTransferDetails::getWaterTransferId, id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void submit(WaterTransferVo waterTransferVo) {

        waterTransferVo.setCheckerId(AuthUtil.getUserId());
        waterTransferVo.setCheckerTime(new Date());
        waterTransferVo.setStatus(StatusConstant.YES);
        updateById(waterTransferVo);

        Long waterTransferId = waterTransferVo.getId();
        Long materialId = waterTransferVo.getMaterialId();
        Long receiveId = waterTransferVo.getReceiveId();
        List<WaterTransferDetails> waterTransferDetailsList = waterTransferVo.getWaterTransferDetailsList();

        for (WaterTransferDetails waterTransferDetails : waterTransferDetailsList) {
            waterTransferDetails.setWaterTransferId(waterTransferId);
            waterTransferDetails.setMaterialId(materialId);
            waterTransferDetails.setReceiveId(receiveId);
            waterTransferDetails.setStatus(StatusConstant.YES);
            if (ObjectUtil.isEmpty(waterTransferDetails.getId())) {
                waterTransferDetails.setOldQuantity(BigDecimal.ZERO);
            }
        }
        waterTransferDetailsService.saveOrUpdateBatch(waterTransferDetailsList);


        List<Long> waterTransferDetailsIdList = waterTransferDetailsList.stream()
                .map(StorageBaseEntity::getId).collect(Collectors.toList());

        waterTransferDetailsService.remove(Wrappers.<WaterTransferDetails>lambdaQuery()
                .eq(WaterTransferDetails::getWaterTransferId, waterTransferId)
                .notIn(StorageBaseEntity::getId, waterTransferDetailsIdList));
    }

    @Override
    public Map<String, Object> statistics(Condition condition) {
        QueryWrapper<Object> wrapper = getWrapper(condition);

        return baseMapper.getStatistics(wrapper);
    }

    @Override
    public Page<Map<String, Object>> getPage(Condition condition) {
        QueryWrapper<Object> wrapper = getWrapper(condition);
        Page<Map<String, Object>> page = baseMapper.getPage(condition.getPage(), wrapper);
        List<Map<String, Object>> records = page.getRecords();
        if (records.size() == 0) {
            return page;
        }

        Set<Long> userIdSet = new HashSet<>();
        for (Map<String, Object> record : records) {
            userIdSet.add(Convert.toLong(record.get("createUser")));
            userIdSet.add(Convert.toLong(record.get("receiveId")));
        }

        Map<Long, String> userNameMap = UserClientUtil.getUserNameMap(userIdSet);

        for (Map<String, Object> record : records) {
            record.put("createUserName", userNameMap.get(Convert.toLong(record.get("createUser"))));
            record.put("receiveUserName", userNameMap.get(Convert.toLong(record.get("receiveId"))));
        }

        return page;
    }

    private QueryWrapper<Object> getWrapper(Condition condition) {
        QueryWrapper<Object> wrapper = Wrappers.query();

        Date beginTime = condition.getBeginTime();
        Date endTime = condition.getEndTime();
        Long userId = condition.getUserId();

        return wrapper
                .eq("wtd.del_flag", StatusConstant.NOT_DELETED)
                .and(ObjectUtil.isNotEmpty(userId), q -> q.eq("wtd.create_user", userId).or().eq("wtd.receive_id", userId))
                .between(ObjectUtil.isAllNotEmpty(beginTime, endTime), "wtd.create_time", beginTime, endTime);
    }

}
