package com.mortals.xhx.module.site.service.impl;

import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.framework.service.impl.AbstractCRUDCacheServiceImpl;
import com.mortals.framework.util.DataUtil;
import com.mortals.framework.util.StringUtils;
import com.mortals.xhx.common.key.Constant;
import com.mortals.xhx.common.utils.SyncTreeSiteThread;
import com.mortals.xhx.module.area.model.AreaEntity;
import com.mortals.xhx.module.area.model.AreaQuery;
import com.mortals.xhx.module.area.model.AreaTreeSelect;
import com.mortals.xhx.module.area.service.AreaService;
import com.mortals.xhx.module.site.model.SiteQuery;
import com.mortals.xhx.module.site.model.SiteTreeSelect;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mortals.framework.service.impl.AbstractCRUDServiceImpl;
import com.mortals.xhx.module.site.dao.SiteDao;
import com.mortals.xhx.module.site.model.SiteEntity;
import com.mortals.xhx.module.site.service.SiteService;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * SiteService
 * 站点 service实现
 *
 * @author zxfei
 * @date 2022-01-12
 */
@Service("siteService")
public class SiteServiceImpl extends AbstractCRUDCacheServiceImpl<SiteDao, SiteEntity, Long> implements SiteService {

    private List<SiteTreeSelect> siteTreeList;

    @Autowired
    private AreaService areaService;

    @Override
    protected void validData(SiteEntity entity, Context context) throws AppException {
        if (ObjectUtils.isEmpty(entity.getAreaCode())) {
            throw new AppException("区域编码不能为空！");
        }
        AreaEntity areaEntity = areaService.getCache(entity.getAreaCode());
        if (ObjectUtils.isEmpty(areaEntity)) {
            throw new AppException(String.format("区域不存在！区域编码：%s", entity.getAreaCode()));
        }
        super.validData(entity, context);
    }

    @Override
    protected void saveBefore(SiteEntity entity, Context context) throws AppException {
        List<SiteEntity> siteEntities = this.find(new SiteQuery().areaCode(entity.getAreaCode()));
        entity.setSiteCode(entity.getAreaCode() + Constant.SITE_SPLIT_MARK + StringUtils.lpad(siteEntities.size() + 1, Constant.SITE_CODE_NUM));
        super.saveBefore(entity, context);
    }

    @Override
    public List<SiteTreeSelect> siteTree(Context context) {
        Map<String, AreaEntity> areaMap = new HashMap<>();
        //查询所有已配置的站点
        List<SiteEntity> siteList = this.find(new SiteQuery());
        Map<String, SiteEntity> siteMap = siteList.parallelStream().collect(Collectors.toMap(x -> x.getSiteCode(), y -> y, (o, n) -> n));
        //遍历过滤站点树
        for (SiteEntity siteEntity : siteList) {
            AreaEntity areaEntity = areaService.getExtCache(siteEntity.getAreaCode());
            //根据区域添加父节点
            if (!ObjectUtils.isEmpty(areaEntity) && !ObjectUtils.isEmpty(areaEntity.getPid())) {
                //递归查找父节点并添加
                areaMap.put(areaEntity.getAreaCode(), areaEntity);
                recursionFn(areaMap, areaEntity);
            }
        }

        return buildSiteTreeSelect(areaMap, siteMap);
    }

    @Override
    public List<SiteTreeSelect> getSiteTree(Context context) {
        return siteTreeList;
    }

    @Override
    public void setSiteTree(List<SiteTreeSelect> list, Context context) {
        this.siteTreeList = list;
    }

    public List<SiteTreeSelect> buildSiteTreeSelect(Map<String, AreaEntity> areaMap, Map<String, SiteEntity> siteMap) {
        List<AreaEntity> list = areaMap.values().stream().collect(Collectors.toList());
        List<AreaEntity> returnList = new ArrayList<>();
        List<String> tempList = list.stream().map(AreaEntity::getIid).collect(Collectors.toList());
        for (AreaEntity areaEntity : list) {
            //查询当前区域列表中最顶级的节点 并构建树
            if (!tempList.contains(areaEntity.getPid())) {
                recursion(list, areaEntity);
                returnList.add(areaEntity);
            }
        }
        if (returnList.isEmpty()) {
            returnList = list;
        }

        List<SiteTreeSelect> collect = returnList.stream().map(item ->
                new SiteTreeSelect(item, siteMap)
        ).collect(Collectors.toList());
        this.siteTreeList = collect;
        return collect;

    }

    private void recursion(List<AreaEntity> list, AreaEntity t) {
        // 得到子节点列表
        List<AreaEntity> childList = getChildList(list, t);
        t.setChildren(childList);
        for (AreaEntity tChild : childList) {
            if (hasChild(list, tChild)) {
                recursion(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<AreaEntity> getChildList(List<AreaEntity> list, AreaEntity t) {
        return list.stream().filter(item -> item.getPid().equals(t.getIid())).collect(Collectors.toList());
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<AreaEntity> list, AreaEntity t) {
        return getChildList(list, t).size() > 0 ? true : false;
    }


    /**
     * 递归列表
     */
    private void recursionFn(Map<String, AreaEntity> areaMap, AreaEntity t) {
        // 得到父节点并加入
        AreaEntity areaEntity = areaService.selectOne(new AreaQuery().iid(t.getPid()));
        if (!ObjectUtils.isEmpty(areaEntity)) {
            areaMap.put(areaEntity.getAreaCode(), areaEntity);
            recursionFn(areaMap, areaEntity);
        }
    }


    @Override
    protected void updateAfter(SiteEntity entity, Context context) throws AppException {
        //刷新站点树
        new Thread(new SyncTreeSiteThread(this,context)).start();
        super.updateAfter(entity, context);
    }

    @Override
    protected void saveAfter(SiteEntity entity, Context context) throws AppException {
        //刷新站点树
        new Thread(new SyncTreeSiteThread(this,context)).start();
        super.saveAfter(entity, context);
    }

    @Override
    protected void removeBefore(Long[] ids, Context context) throws AppException {
        new Thread(new SyncTreeSiteThread(this,context)).start();
        super.removeBefore(ids, context);
    }
}