package ink.wgink.module.dictionary.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.module.dictionary.dao.IAreaDao;
import ink.wgink.module.dictionary.pojo.dtos.AreaDTO;
import ink.wgink.module.dictionary.pojo.vos.AreaVO;
import ink.wgink.module.dictionary.service.IAreaService;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.dtos.ZTreeDTO;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.util.map.HashMapUtil;
import ink.wgink.util.string.WStringUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: AreaServiceImpl
 * @Description: 字典
 * @Author: WangGeng
 * @Date: 2019/11/18 14:09
 * @Version: 1.0
 **/
@Service
public class AreaServiceImpl extends DefaultBaseService implements IAreaService {

    @Autowired
    private IAreaDao areaDao;
    /**
     * 更新合并和短标题线程池
     */
    private static ExecutorService UPDATE_MERGER_SHORT_NAME_EXECUTOR_SERVICE = Executors.newFixedThreadPool(66);

    @Override
    public void save(AreaVO areaVO) {
        saveReturnId(areaVO);
    }

    @Override
    public String saveReturnId(AreaVO areaVO) {
        Map<String, Object> params = HashMapUtil.beanToMap(areaVO);
        setSaveInfo(params);
        areaDao.save(params);
        return params.get("areaId").toString();
    }

    @Override
    public void remove(List<String> ids) {
        Map<String, Object> params = getHashMap(3);
        params.put("areaIds", ids);
        setUpdateInfo(params);
        areaDao.remove(params);
    }

    @Override
    public void update(String areaId, AreaVO areaVO) {
        Map<String, Object> params = HashMapUtil.beanToMap(areaVO);
        params.put("areaId", areaId);
        setUpdateInfo(params);
        areaDao.update(params);
    }

    @Override
    public AreaDTO get(String areaId) {
        Map<String, Object> params = super.getHashMap(1);
        params.put("areaId", areaId);
        return areaDao.get(params);
    }

    @Override
    public AreaDTO getByCode(String areaCode) {
        Map<String, Object> params = getHashMap(2);
        params.put("areaCode", areaCode);
        return areaDao.get(params);
    }

    @Override
    public List<AreaDTO> listFullLevel(String areaId) {
        AreaDTO areaDTO = get(areaId);
        List<AreaDTO> fullLevelAreaDTOS = new ArrayList<>();
        fullLevelAreaDTOS.add(0, areaDTO);
        setFullLevel(fullLevelAreaDTOS, areaDTO.getAreaParentId());
        return fullLevelAreaDTOS;
    }

    @Override
    public List<AreaDTO> list() {
        Map<String, Object> params = getHashMap(0);
        return areaDao.list(params);
    }

    @Override
    public List<AreaDTO> listByParentId(String areaParentId) {
        Map<String, Object> params = getHashMap(1);
        params.put("areaParentId", areaParentId);
        return areaDao.list(params);
    }

    @Override
    public List<AreaDTO> listAllByParentId(String areaParentId) {
        Map<String, Object> params = getHashMap(1);
        params.put("areaParentId", areaParentId);
        List<AreaDTO> dataAreaDTOs = areaDao.list(params);
        listSub(dataAreaDTOs, params);
        return dataAreaDTOs;
    }

    @Override
    public SuccessResultList<List<AreaDTO>> listPage(ListPage page) {
        PageHelper.startPage(page.getPage(), page.getRows());
        List<AreaDTO> dataAreaDTOs = areaDao.list(page.getParams());
        PageInfo<AreaDTO> pageInfo = new PageInfo<>(dataAreaDTOs);
        return new SuccessResultList<>(dataAreaDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public List<ZTreeDTO> listZTree(Map<String, Object> params) {
        List<ZTreeDTO> zTreeDTOs = areaDao.listZTree(params);
        for (ZTreeDTO zTreeDTO : zTreeDTOs) {
            Integer subCount = areaDao.countByParentId(zTreeDTO.getId());
            setZTreeInfo(zTreeDTO, subCount);
        }
        return zTreeDTOs;
    }

    @Override
    public List<AreaDTO> listByCode(String areaCode) {
        Map<String, Object> params = getHashMap(1);
        params.put("areaCode", WStringUtil.cutContinuityRepeatCharDesc(areaCode, '0', 3));
        return areaDao.list(params);
    }

    @Override
    public List<AreaDTO> listByCodes(List<String> areaCodes) {
        if (areaCodes == null || areaCodes.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(1);
        params.put("areaCodes", areaCodes);
        return areaDao.list(params);
    }

    @Override
    public List<AreaDTO> listSubByCode(String areaCode) {
        Map<String, Object> params = getHashMap(4);
        params.put("areaCode", WStringUtil.cutContinuityRepeatCharDesc(areaCode, '0', 3));
        params.put("excludeAreaCode", areaCode);
        return areaDao.list(params);
    }

    @Override
    public void updateShortAndMergerName() {
        if (isUpdateShortAndMergerName()) {
            return;
        }
        Map<String, Object> params = getHashMap(2);
        Integer count = areaDao.count(params);
        int row = 1000;
        int totalPage = row % 1000 == 0 ? count / row : (count / row + 1);
//        int totalPage = 1;
        for (int currentPage = 1; currentPage <= totalPage; currentPage++) {
            updateShortAndMergerName(currentPage, totalPage, row);
        }
    }

    /**
     * 是否正在更新
     *
     * @return
     */
    private boolean isUpdateShortAndMergerName() {
        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) UPDATE_MERGER_SHORT_NAME_EXECUTOR_SERVICE;
        return threadPoolExecutor.getQueue().size() != 0 || threadPoolExecutor.getActiveCount() != 0;
    }


    private void updateShortAndMergerName(int currentPage, int totalPage, int row) {
        if (currentPage > totalPage) {
            return;
        }
        UPDATE_MERGER_SHORT_NAME_EXECUTOR_SERVICE.execute(() -> {
            int limitStart = (currentPage - 1) * row;
            Map<String, Object> params = getHashMap(2);
            params.put("limitStart", limitStart);
            params.put("limitRow", row);
            List<AreaDTO> areaDTOS = areaDao.listPage(params);
            if (areaDTOS.isEmpty()) {
                return;
            }
            areaDTOS.forEach(areaDTO -> {
                List<AreaDTO> fullLevelAreaDTOS = new ArrayList<>();
                fullLevelAreaDTOS.add(0, areaDTO);
                setFullLevel(fullLevelAreaDTOS, areaDTO.getAreaParentId());
                // 完整的地区名称
                String areaMergerName = "";
                for (AreaDTO fullLevelAreaDTO : fullLevelAreaDTOS) {
                    areaMergerName += fullLevelAreaDTO.getAreaName();
                }
                String areaShortName = getAreaShortName(areaDTO.getAreaName());
                params.clear();
                params.put("areaId", areaDTO.getAreaId());
                params.put("areaMergerName", areaMergerName);
                params.put("areaShortName", areaShortName);
                areaDao.updateShortAndMergerName(params);
            });
        });
    }

    /**
     * 获取短名称
     *
     * @param areaName
     * @return
     */
    private String getAreaShortName(String areaName) {
        String areaShortName = areaName;
        if (areaName.endsWith("市")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 1);
        } else if (areaName.endsWith("省")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 1);
        } else if (areaName.endsWith("自治区")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 3);
        } else if (areaName.endsWith("旗")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 1);
        } else if (areaName.endsWith("县")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 1);
        } else if (areaName.endsWith("社区")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 2);
        } else if (areaName.endsWith("区")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 1);
        } else if (areaName.endsWith("乡")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 1);
        } else if (areaName.endsWith("镇")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 1);
        } else if (areaName.endsWith("街道")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 2);
        } else if (areaName.endsWith("居委会")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 2);
        } else if (areaName.endsWith("嘎查村")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 3);
        } else if (areaName.endsWith("村")) {
            areaShortName = areaShortName.substring(0, areaShortName.length() - 1);
        }
        return areaShortName;
    }

    /**
     * 设置完整级别
     *
     * @param fullLevelAreaDTOS
     * @param areaParentId
     */
    private void setFullLevel(List<AreaDTO> fullLevelAreaDTOS, String areaParentId) {
        if (StringUtils.equals(ISystemConstant.TREE_ROOT_ID, areaParentId)) {
            return;
        }
        AreaDTO areaDTO = get(areaParentId);
        fullLevelAreaDTOS.add(0, areaDTO);
        setFullLevel(fullLevelAreaDTOS, areaDTO.getAreaParentId());
    }

    /**
     * 递归查询子组
     *
     * @param dataAreaDTOs
     * @param params
     */
    private void listSub(List<AreaDTO> dataAreaDTOs, Map<String, Object> params) {
        for (AreaDTO dataAreaDTO : dataAreaDTOs) {
            params.put("areaParentId", dataAreaDTO.getAreaId());
            List<AreaDTO> subAreaDTOS = areaDao.list(params);
            dataAreaDTO.setSubArea(subAreaDTOS);
            listSub(subAreaDTOS, params);
        }
    }
}
