package com.fjhx.service.water.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
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.DetpIdConstant;
import com.fjhx.constants.StatusConstant;
import com.fjhx.entity.material.Material;
import com.fjhx.entity.water.WaterBack;
import com.fjhx.entity.water.WaterBackDetails;
import com.fjhx.feign.IUserClient;
import com.fjhx.mapper.water.WaterBackMapper;
import com.fjhx.params.water.WaterBackAddVo;
import com.fjhx.params.water.WaterBackVo;
import com.fjhx.service.material.MaterialService;
import com.fjhx.service.water.WaterBackDetailsService;
import com.fjhx.service.water.WaterBackService;
import com.fjhx.utils.Assert;
import com.fjhx.utils.UserClientUtil;
import org.springblade.core.mp.base.BaseEntity;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.system.user.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import springfox.documentation.spring.web.json.Json;

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

/**
 * <p>
 * 退料 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-10-27
 */
@Service
public class WaterBackServiceImpl extends ServiceImpl<WaterBackMapper, WaterBack> implements WaterBackService {

    @Autowired
    private WaterBackDetailsService waterBackDetailsService;

    @Autowired
    private MaterialService materialService;

    @Autowired
    private IUserClient userClient;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(List<WaterBackAddVo> waterBackAddVoList) {
        WaterBack waterBack = new WaterBack();
        waterBack.setNumber(
                waterBackAddVoList.stream().map(item -> item.getQuantityList().size()).reduce(0, Integer::sum));
        waterBack.setQuantity(waterBackAddVoList.stream()
                .map(item -> item.getQuantityList().stream().reduce(BigDecimal.ZERO, BigDecimal::add))
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        waterBack.setStatus(StatusConstant.NO);
        save(waterBack);


        List<WaterBackDetails> waterBackDetailsList = new ArrayList<>();
        for (WaterBackAddVo waterBackAddVo : waterBackAddVoList) {
            Long materialId = waterBackAddVo.getMaterialId();
            List<BigDecimal> quantityList = waterBackAddVo.getQuantityList();

            for (BigDecimal quantity : quantityList) {
                WaterBackDetails waterBackDetails = new WaterBackDetails();
                waterBackDetails.setWaterBackId(waterBack.getId());
                waterBackDetails.setMaterialId(materialId);
                waterBackDetails.setQuantity(quantity);
                waterBackDetails.setOldQuantity(quantity);
                waterBackDetails.setStatus(StatusConstant.NO);
                waterBackDetailsList.add(waterBackDetails);
            }
        }
        waterBackDetailsService.saveBatch(waterBackDetailsList);

    }

    @Override
    public List<Map<String, Object>> toBeReviewedList() {
        List<Map<String, Object>> list = listMaps(Wrappers.<WaterBack>lambdaQuery()
                .eq(WaterBack::getStatus, StatusConstant.NO));

        // 赋值用户名称
        UserClientUtil.setUserName(list, "createUser", "createUserName");

        return list;
    }

    @Override
    public List<Map<String, Object>> details(Long waterBackId) {
        List<WaterBackDetails> list = waterBackDetailsService.list(WaterBackDetails::getWaterBackId, waterBackId);
        if (list.size() == 0) {
            return new ArrayList<>();
        }

        Map<Long, Map<String, Object>> collect = list.stream().collect(Collectors.toMap(
                WaterBackDetails::getMaterialId,
                item -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("id", waterBackId);
                    map.put("materialId", item.getMaterialId());
                    map.put("list", Collections.singletonList(item));
                    return map;
                },
                (v1, v2) -> {
                    List<WaterBackDetails> item1List = new ArrayList<>((List<WaterBackDetails>) v1.get("list"));
                    List<WaterBackDetails> item2List = new ArrayList<>((List<WaterBackDetails>) v2.get("list"));
                    item1List.addAll(item2List);

                    v1.put("list", item1List);
                    return v1;
                }
        ));

        // 查询物料名称
        Map<Long, String> materialNameMap = materialService.listByIds(collect.keySet()).stream()
                .collect(Collectors.toMap(StorageBaseEntity::getId, Material::getName));

        List<Map<String, Object>> result = new ArrayList<>(collect.values());

        // 赋值物料名称
        for (Map<String, Object> map : result) {
            map.put("materialName", materialNameMap.get(Convert.toLong(map.get("materialId"))));
        }

        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Long waterBackId) {
        removeById(waterBackId);
        waterBackDetailsService.remove(WaterBackDetails::getWaterBackId, waterBackId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void submit(WaterBackVo waterBackVo) {
        Long waterBackId = waterBackVo.getId();
        waterBackVo.setStatus(StatusConstant.YES);
        waterBackVo.setCheckerId(AuthUtil.getUserId());
        waterBackVo.setCheckerTime(new Date());
        updateById(waterBackVo);

        List<WaterBackDetails> waterBackDetailsList = waterBackVo.getWaterBackDetailsList();

        for (WaterBackDetails waterBackDetails : waterBackDetailsList) {
            waterBackDetails.setStatus(StatusConstant.YES);
            if (ObjectUtil.isEmpty(waterBackDetails.getId())) {
                waterBackDetails.setWaterBackId(waterBackId);
                waterBackDetails.setOldQuantity(BigDecimal.ZERO);
            }
        }
        waterBackDetailsService.saveOrUpdateBatch(waterBackDetailsList);

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

        waterBackDetailsService.remove(Wrappers.<WaterBackDetails>lambdaQuery()
                .eq(WaterBackDetails::getWaterBackId, waterBackId)
                .notIn(StorageBaseEntity::getId, waterBackIdList));
    }

    @Override
    public Map<String, JSONObject> getUserByAppointDept() {

        List<Long> list = Arrays.asList(DetpIdConstant.JET_PRINT, DetpIdConstant.TRANSFER, DetpIdConstant.TYPING);

        R<List<User>> userListByDeptIdListR = userClient.getUserListByDeptIdList(list);
        List<User> userList = Assert.result(userListByDeptIdListR);

        return userList.stream().collect(Collectors.toMap(
                item -> {
                    String deptId = item.getDeptId();
                    if (deptId.contains(DetpIdConstant.JET_PRINT.toString())) {
                        return "jetPrint";
                    } else if (deptId.contains(DetpIdConstant.TYPING.toString())) {
                        return "typing";
                    } else {
                        return "transfer";
                    }
                },
                item -> {
                    JSONObject map = new JSONObject();
                    String deptId = item.getDeptId();

                    if (deptId.contains(DetpIdConstant.JET_PRINT.toString())) {
                        map.put("deptName", "直喷");
                        map.put("deptId", DetpIdConstant.JET_PRINT);
                    } else if (deptId.contains(DetpIdConstant.TYPING.toString())) {
                        map.put("deptName", "打纸");
                        map.put("deptId", DetpIdConstant.TYPING);
                    } else {
                        map.put("deptName", "热转");
                        map.put("deptId", DetpIdConstant.TRANSFER);
                    }

                    JSONObject user = new JSONObject();
                    user.put("id",item.getId());
                    user.put("name",item.getName());
                    map.put("list", Collections.singletonList(user));
                    return map;
                },
                (v1, v2) -> {
                    List<JSONObject> v1List = new ArrayList<>((List<JSONObject>) v1.get("list"));
                    List<JSONObject> v2List = new ArrayList<>((List<JSONObject>) v2.get("list"));
                    v1List.addAll(v2List);
                    v1.put("list", v1List);
                    return v1;
                }
        ));
    }

    @Override
    public List<Long> getUserIdByAppointDept(Long... deptId) {
        List<Long> list = Arrays.asList(deptId);
        R<List<User>> userListByDeptIdListR = userClient.getUserListByDeptIdList(list);
        List<User> userList = Assert.result(userListByDeptIdListR);

        return userList.stream().map(BaseEntity::getId).collect(Collectors.toList());
    }

    @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;
        }

        // 赋值用户名称
        UserClientUtil.setUserName(records, "createUser", "createUserName");

        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("wbd.del_flag", StatusConstant.NOT_DELETED)
                .eq(ObjectUtil.isNotEmpty(userId), "wbd.create_user", userId)
                .between(ObjectUtil.isAllNotEmpty(beginTime, endTime), "wbd.create_time", beginTime, endTime);
    }

}
