package com.inspect.metadata.area.service.impl;

import com.inspect.metadata.area.domain.BaseDataArea;
import com.inspect.metadata.area.domain.vo.TreeSelect;
import com.inspect.metadata.area.mapper.BaseDataAreaMapper;
import com.inspect.metadata.area.service.IBaseDataAreaService;
import com.inspect.metadata.prodevmnt.domain.TreeModule;
import com.inspect.base.core.exception.ServiceException;
import com.inspect.base.core.text.Convert;
import com.inspect.base.core.utils.SpringUtils;
import com.inspect.base.core.utils.StringUtils;
import com.inspect.common.aspect.annotation.DataScope;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

@Service
public class BaseDataAreaServiceImpl implements IBaseDataAreaService {
    private final BaseDataAreaMapper baseDataAreaMapper;
    public static final String BASE_NUMBER = "0123456789";

    public BaseDataAreaServiceImpl(BaseDataAreaMapper baseDataAreaMapper) {
        this.baseDataAreaMapper = baseDataAreaMapper;
    }

    @DataScope(
            deptAlias = "d"
    )
    public List<BaseDataArea> selectAreaList(BaseDataArea area) {
        return this.baseDataAreaMapper.selectAreaList(area);
    }

    @DataScope(
            deptAlias = "d"
    )
    public List<BaseDataArea> selectAreaRelationList(BaseDataArea area) {
        return this.baseDataAreaMapper.selectAreaRelationList(area);
    }

    public List buildAreaTree(List<BaseDataArea> areas) {
        List<BaseDataArea> returnList = new ArrayList<>();
        List<Long> tempList = new ArrayList<>();
        Iterator<BaseDataArea> iterator = areas.iterator();

        BaseDataArea area;
        while (iterator.hasNext()) {
            area = iterator.next();
            tempList.add(area.getAreaId());
        }

        iterator = areas.iterator();
        while (iterator.hasNext()) {
            area = iterator.next();
            if (!tempList.contains(area.getParentId())) {
                this.recursionFn(areas, area);
                returnList.add(area);
            }
        }

        if (returnList.isEmpty()) {
            returnList = areas;
        }

        return returnList;
    }

    public List buildAreaTreeSelect(List<BaseDataArea> areas) {
        List<BaseDataArea> deptTrees = this.buildAreaTree(areas);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    public List<TreeModule> buildAreaTreeAgain(List<BaseDataArea> areas) {
        List<BaseDataArea> deptTrees = this.buildAreaTree(areas);
        return deptTrees.stream().map(TreeModule::new).collect(Collectors.toList());
    }

    public List<Long> selectAreaListByRoleId(Long roleId) {
        return null;
    }

    public BaseDataArea selectAreaById(Long areaId) {
        return this.baseDataAreaMapper.selectAreaById(areaId);
    }

    public BaseDataArea selectAreaRelationById(Long areaId) {
        return this.baseDataAreaMapper.selectAreaRelationById(areaId);
    }

    @Override
    public void updateAreaRelationById(Long areaId, Long toAreaId, String ancestors) {
        this.baseDataAreaMapper.updateAreaRelationById(areaId, toAreaId, ancestors);
    }

    public int selectNormalChildrenAreaById(Long areaId) {
        return this.baseDataAreaMapper.selectNormalChildrenAreaById(areaId);
    }

    public boolean hasChildByAreaId(Long areaId) {
        int result = this.baseDataAreaMapper.hasChildByAreaId(areaId);
        return result > 0;
    }

    public boolean checkAreaExistUser(Long areaId) {
        int result = this.baseDataAreaMapper.checkAreaExistBook(areaId);
        return result > 0;
    }

    public String checkAreaNameUnique(BaseDataArea area) {
        Long areaId = StringUtils.isNull(area.getAreaId()) ? -1L : area.getAreaId();
        BaseDataArea info = this.baseDataAreaMapper.checkAreaNameUnique(area.getAreaName(), area.getParentId());
        return StringUtils.isNotNull(info) && info.getAreaId().longValue() != areaId.longValue() ? "1" : "0";
    }

    public void checkAreaDataScope(Long areaId) {
        BaseDataArea area = new BaseDataArea();
        area.setAreaId(areaId);
        List<BaseDataArea> areas = SpringUtils.getAopProxy(this).selectAreaList(area);
        if (StringUtils.isEmpty(areas)) {
            throw new ServiceException("没有权限访问区域数据！");
        }
    }

    public int insertArea(BaseDataArea area) {
        area.setDeviceTypeCode(getRandomNum());
        BaseDataArea info = this.baseDataAreaMapper.selectAreaById(area.getParentId());
        if (!"0".equals(info.getStatus())) {
            throw new ServiceException("区域停用，不允许新增");
        } else {
            area.setAncestors(info.getAncestors() + "," + area.getParentId());
            return this.baseDataAreaMapper.insertArea(area);
        }
    }

    public int updateArea(BaseDataArea area) {
        BaseDataArea newParentArea = this.baseDataAreaMapper.selectAreaById(area.getParentId());
        BaseDataArea oldRegion = this.baseDataAreaMapper.selectAreaById(area.getAreaId());
        if (StringUtils.isNotNull(newParentArea) && StringUtils.isNotNull(oldRegion)) {
            String newAncestors = newParentArea.getAncestors() + "," + newParentArea.getAreaId();
            String oldAncestors = oldRegion.getAncestors();
            area.setAncestors(newAncestors);
            this.updateAreaChildren(area.getAreaId(), newAncestors, oldAncestors);
        }

        int result = this.baseDataAreaMapper.updateArea(area);
        if ("0".equals(area.getStatus()) && StringUtils.isNotEmpty(area.getAncestors()) && !StringUtils.equals("0", area.getAncestors())) {
            this.updateParentAreaStatusNormal(area);
        }

        return result;
    }

    private void updateParentAreaStatusNormal(BaseDataArea area) {
        String ancestors = area.getAncestors();
        Long[] areaIds = Convert.toLongArray(ancestors);
        this.baseDataAreaMapper.updateAreaStatusNormal(areaIds);
    }

    public void updateAreaChildren(Long areaId, String newAncestors, String oldAncestors) {
        List<BaseDataArea> children = this.baseDataAreaMapper.selectChildrenAreaById(areaId);

        for (BaseDataArea child : children) {
            child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
        }

        if (!children.isEmpty()) {
            this.baseDataAreaMapper.updateAreaChildren(children);
        }

    }

    public int deleteAreaById(Long areaId) {
        return this.baseDataAreaMapper.deleteAreaById(areaId);
    }

    private void recursionFn(List<BaseDataArea> list, BaseDataArea t) {
        List<BaseDataArea> childList = this.getChildList(list, t);
        t.setChildren(childList);
        for (BaseDataArea tChild : childList) {
            if (this.hasChild(list, tChild)) {
                this.recursionFn(list, tChild);
            }
        }

    }

    private List<BaseDataArea> getChildList(List<BaseDataArea> list, BaseDataArea t) {
        List<BaseDataArea> tlist = new ArrayList<>();
        for (BaseDataArea n : list) {
            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getAreaId().longValue()) {
                tlist.add(n);
            }
        }

        return tlist;
    }

    private boolean hasChild(List<BaseDataArea> list, BaseDataArea t) {
        return !this.getChildList(list, t).isEmpty();
    }

    public BaseDataArea selectBasedataAreaByPatrolPointId(String patrolPointId) {
        return this.baseDataAreaMapper.selectBasedataAreaByPatrolPointId(patrolPointId);
    }

    public String selectAreaIdByName(String areaName, String parentId) {
        return this.baseDataAreaMapper.selectAreaIdByName(areaName, parentId);
    }

    public Map<String, Long> selectAreaForNamePatch(BaseDataArea area) {
        List<BaseDataArea> areas = this.baseDataAreaMapper.selectAreaList(area);
        HashMap<String, Long> idNamePathMap = new HashMap<>();
        HashMap<Long, String> idNameMap = new HashMap<>();
        HashMap<Long, Long> idPidMap = new HashMap<>();
        if (!areas.isEmpty()) {
            Iterator<BaseDataArea> iterator = areas.iterator();

            BaseDataArea dataArea;
            Long areaId;
            String areaName;
            while (iterator.hasNext()) {
                dataArea = iterator.next();
                areaId = dataArea.getAreaId();
                Long parentId = dataArea.getParentId();
                areaName = dataArea.getAreaName();
                idNameMap.put(areaId, areaName);
                idPidMap.put(areaId, parentId);
            }

            iterator = areas.iterator();

            while (iterator.hasNext()) {
                dataArea = iterator.next();
                areaId = dataArea.getAreaId();
                StringBuilder builder = new StringBuilder();
                areaName = dataArea.getAreaName();
                builder.append(areaName);
                Long parentId = dataArea.getParentId();
                if (idNameMap.containsKey(parentId)) {
                    this.recursionAreaToNameId(builder, parentId, idNameMap, idPidMap);
                }

                String name = builder.toString();
                idNamePathMap.put(name, areaId);
            }
        }

        return idNamePathMap;
    }

    private void recursionAreaToNameId(StringBuilder builder, Long parId, HashMap<Long, String> idNameMap, HashMap<Long, Long> idPidMap) {
        String areaName;
        if (idNameMap.containsKey(parId)) {
            areaName = idNameMap.get(parId);
            builder.insert(0, areaName + "/");
            parId = idPidMap.get(parId);
            if (idNameMap.containsKey(parId)) {
                this.recursionAreaToNameId(builder, parId, idNameMap, idPidMap);
            }
        } else {
            areaName = idNameMap.get(parId);
            builder.insert(0, areaName);
        }

    }

    public static String getRandomNum() {
        StringBuilder sb = new StringBuilder(6);

        for (int i = 0; i < 6; ++i) {
            int num;
            for (num = ThreadLocalRandom.current().nextInt(BASE_NUMBER.length()); num == 0 && i == 0; num = ThreadLocalRandom.current().nextInt(BASE_NUMBER.length())) {
                ;
            }

            sb.append(BASE_NUMBER.charAt(num));
        }

        return sb.toString();
    }

    public static void main(String[] args) {
        int i = 0;

        while (i < 30) {
            ++i;
            System.out.println(getRandomNum());
        }

    }
}
