package com.yeejoin.equipmanage.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yeejoin.equipmanage.common.entity.StockDetail;
import com.yeejoin.equipmanage.common.entity.Warehouse;
import com.yeejoin.equipmanage.common.entity.WarehouseStructure;
import com.yeejoin.equipmanage.mapper.WarehouseStructureMapper;
import com.yeejoin.equipmanage.service.IStockDetailService;
import com.yeejoin.equipmanage.service.IWarehouseService;
import com.yeejoin.equipmanage.service.IWarehouseStructureService;

/**
 * 货架结构 服务实现类
 *
 * @author wujiang
 * @date 2020-07-07
 */
@Service
public class WarehouseStructureServiceImpl extends ServiceImpl<WarehouseStructureMapper, WarehouseStructure>
        implements IWarehouseStructureService {

    @Autowired
    private IStockDetailService iStockDetailService;

    @Autowired
    IWarehouseService iWarehouseService;

    @Autowired
    private WarehouseStructureMapper warehouseStructureMapper;

    @Override
    public WarehouseStructure saveOne(WarehouseStructure warehouseStructure) {
        String code = generateCode(warehouseStructure);
        warehouseStructure.setCode(code);
        WarehouseStructure parent = getById(warehouseStructure.getParentId());
        if (parent != null) {
            warehouseStructure.setCellCode(parent.getCellCode() + code);
            warehouseStructure.setFullName(parent.getFullName() + "-" + warehouseStructure.getName());
        } else {
            warehouseStructure.setCellCode(code);
            warehouseStructure.setFullName(warehouseStructure.getName());
        }
        save(warehouseStructure);
        return warehouseStructure;
    }

    @Override
    public List<WarehouseStructure> tree(Long warehouseId) {
        Map<String, Object> columnMap = new HashMap<String, Object>();
        columnMap.put("warehouse_id", warehouseId);
        List<WarehouseStructure> list = (List<WarehouseStructure>) listByMap(columnMap);
        list = buildByRecursive(list,warehouseId);
        return list;
    }

    /**
     * 生成code
     * 
     * @param warehouseStructure
     * @return
     */
    private String generateCode(WarehouseStructure warehouseStructure) {
        Map<String, Object> columnMap = new HashMap<String, Object>();
        columnMap.put("parent_id", warehouseStructure.getParentId());
        List<WarehouseStructure> list = (List<WarehouseStructure>) listByMap(columnMap);
        int code = 0;
        for (WarehouseStructure ws : list) {
            int wcode = Integer.valueOf(ws.getCode());
            if (wcode > code) {
                code = wcode;
            }
        }
        return "0" + ++code;
    }

    /**
     * 使用递归方法建树
     * 
     * @param treeNodes
     * @return
     */
    private List<WarehouseStructure> buildByRecursive(List<WarehouseStructure> treeNodes,Long id) {
        List<WarehouseStructure> trees = new ArrayList<WarehouseStructure>();
        for (WarehouseStructure treeNode : treeNodes) {
            if (null == treeNode.getParentId()|| id.equals(treeNode.getParentId())) {
                trees.add(findChildren(treeNode, treeNodes));
            }
        }
        return trees;
    }

    /**
     * 递归查找子节点
     * 
     * @param treeNodes
     * @return
     */
    private WarehouseStructure findChildren(WarehouseStructure treeNode, List<WarehouseStructure> treeNodes) {
        for (WarehouseStructure it : treeNodes) {
            if (treeNode.getId().equals(it.getParentId())) {
                if (treeNode.getChildren() == null) {
                    treeNode.setChildren(new ArrayList<WarehouseStructure>());
                }
                treeNode.getChildren().add(findChildren(it, treeNodes));
            }
        }
        return treeNode;
    }

    @Override
    public WarehouseStructure updateOneById(WarehouseStructure warehouseStructure) {
        WarehouseStructure old = getById(warehouseStructure.getId());
        WarehouseStructure parent = getById(old.getParentId());
        if (parent != null) {
            warehouseStructure.setFullName(parent.getFullName() + "-" + warehouseStructure.getName());
        } else {
            warehouseStructure.setFullName(warehouseStructure.getName());
        }
        updateById(warehouseStructure);
        updateFullName(warehouseStructure);
        return warehouseStructure;
    }

    /**
     * 递归更新子节点全称
     * 
     * @param warehouseStructure
     */
    private void updateFullName(WarehouseStructure warehouseStructure) {
        Map<String, Object> columnMap = new HashMap<String, Object>();
        columnMap.put("parent_id", warehouseStructure.getId());
        List<WarehouseStructure> list = (List<WarehouseStructure>) listByMap(columnMap);
        if (list.size() > 0) {
            for (WarehouseStructure ws : list) {
                ws.setFullName(warehouseStructure.getFullName() + "-" + ws.getName());
                updateFullName(ws);
            }
            updateBatchById(list);
        }
    }

    @Override
    public boolean removeOneById(Long id) throws Exception {
        WarehouseStructure warehouseStructure = getById(id);
        if (warehouseStructure != null) {
            Map<String, Object> columnMap = new HashMap<String, Object>();
            columnMap.put("parent_id", warehouseStructure.getId());
            List<WarehouseStructure> list = (List<WarehouseStructure>) listByMap(columnMap);
            if (list.size() > 0) {
                throw new Exception("存在子节点，无法删除");
            }
            removeById(id);
        }
        return true;
    }

    @Override
    public boolean removeBatchById(List<Long> idList) throws Exception {
        for (Long id : idList) {
            int count = this.count(new QueryWrapper<WarehouseStructure>().eq("parent_id", id));
            if (count > 0) {
                throw new Exception("存在父节点引用，无法删除");
            }
            int usecount = iStockDetailService.count(new QueryWrapper<StockDetail>().eq("warehouse_structure_id", id));
            if (usecount > 0) {
                throw new Exception("存在装备引用，无法删除");
            }
        }
        this.removeByIds(idList);
        return true;
    }

    @Override
    public String doSaveAutoSysSyn(Warehouse source, Warehouse w) {
        // 敲重点source中id是源数据的中的pid，借用字段传输。SourceId才是源数据ID。sourceCode是源数据的code。name不解释
        String check = saveCheck(source);
        if (check != null) {
            return check;
        }
        QueryWrapper<WarehouseStructure> q = new QueryWrapper<>();
        // source_id有唯一约束
        q.eq("source_id", source.getSourceId());
        WarehouseStructure ws = warehouseStructureMapper.selectOne(q);
        
        boolean add = false;
        // 如果没有查出来说明是新增
        if (ws == null) {
            ws = new WarehouseStructure();
            add = true;
        }
        
        String name = source.getName();
        if(name.length() > 50) {
            // 货架NAME长度只有50源数据库长度255.
            ws.setName(name.substring(0, 50));
        }else {
            ws.setName(name);
        }
        // FullName长度255，无所谓
        ws.setFullName(name);
        
        ws.setSourceId(source.getSourceId());
        ws.setSourceCode(source.getSourceCode());
        WarehouseStructure parent = null;
        // 如果父节点是仓库，说明是货架的顶层
        if (w != null) {
            ws.setWarehouseId(w.getId());
            ws.setParentId(null);
        } else {
            // 两把ID与parentId不是一回事，这里借用实体bean的ID传输原始parentId。新增数据是没有ID的
            Long parentId = source.getId();
            q = new QueryWrapper<>();
            // source_id有唯一约束
            q.eq("source_id", parentId);
            parent = warehouseStructureMapper.selectOne(q);
            // 找不到父节点说明数据有问题
            if (parent == null) {
                return "远程父节点丢失，请同步数据后重试！";
            }
            // 仓库ID和父节点保持一致
            ws.setWarehouseId(parent.getWarehouseId());
            ws.setParentId(parent.getId());
            // 有父节点FullName需要计算
            ws.setFullName(parent.getFullName() + "-" + ws.getName());
        }
        if (add) {
            // 更新数据不动code。新建需要重新计算code
            String code = generateCode(ws);
            ws.setCode(code);
            if(ws.getParentId() == null) {
                ws.setCellCode(ws.getCode());
            }else {
                ws.setCellCode(parent.getCellCode() + code);
            }
            save(ws);
        } else {
            // 有的话就是更新，这里需要校验一下数据是否被引用而不能进行更新。
            String useCheck = saveUseCheck(source, ws, w, parent);
            if (useCheck != null) {
                return useCheck;
            }
            updateById(ws);
        }
        return null;
    }

    /**
     * 更新前占用检查，如果某些数据被别的地方引用后，可能不能修改修改。具体规则根据需求来 。
     *
     * @param source 源数据
     * @param ws 
     * @param w
     * @param parent
     * @return String
     * @throws <br>
     * @author 张展弋
     * @date 2020-9-8 19:16:20
     */
    private String saveUseCheck(Warehouse source, WarehouseStructure ws, Warehouse w, WarehouseStructure parent) {
        // 如果父节点是仓库，说明是货架的顶层
        if (w != null) {
        } else {
            // parent 父节点是货架
        }
        return null;
    }

    /**
     * 
     * SAVE前占用检查。
     * 
     * @param source
     * @return String
     * @throws <br>
     * @author 张展弋
     * @date 2020-9-8 19:09:33
     */
    private String saveCheck(Warehouse source) {
        String sourceCode = source.getSourceCode();
        if (sourceCode == null) {
            return "远程同步时code不能为空！";
        }
        return null;
    }

    @Override
    public String deleteAutoSysSyn(Long sourceId) {
        QueryWrapper<WarehouseStructure> q = new QueryWrapper<>();
        // source_id有唯一约束
        q.eq("source_id", sourceId);
        WarehouseStructure ws = warehouseStructureMapper.selectOne(q);
        // 没找到说明没有直接忽略
        if(ws == null) {
            return null;
        }
        try {
            // 删除直接调用之前的删除方法。此方法中有不可删校验
            removeBatchById(Arrays.asList(ws.getId()));
        } catch (Exception e) {
            // 这种通过异常作为参数返回的方式666、、233333
            return e.getMessage();
        }
        return null;
    }
}
