package com.cool.store.service.impl;

import com.alibaba.excel.util.DateUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.CommonConstants;
import com.cool.store.dao.EnterpriseUserDAO;
import com.cool.store.dao.HyOpenAreaInfoDAO;
import com.cool.store.entity.EnterpriseUserDO;
import com.cool.store.entity.HyOpenAreaInfoDO;
import com.cool.store.enums.AreaStatusEnum;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.mapper.HyOpenAreaInfoMapper;
import com.cool.store.request.OpenAreaRequest;
import com.cool.store.service.OpenAreaService;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.vo.OpenAreaTreeVO;
import com.cool.store.vo.OpenAreaVO;
import com.cool.store.vo.OpenProvinceVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author suzhuhong
 * @Date 2023/6/13 22:11
 * @Version 1.0
 */
@Slf4j
@Service
public class OpenAreaServiceImpl implements OpenAreaService {

    @Resource
    private HyOpenAreaInfoDAO hyOpenAreaInfoDAO;
    @Resource
    private HyOpenAreaInfoMapper hyOpenAreaInfoMapper;
    @Resource
    private RedisUtilPool redisUtilPool;
    @Resource
    EnterpriseUserDAO enterpriseUserDAO;


    @Override
    public List<OpenAreaTreeVO> queryByKeyword(String keyword,String areaStatus,Boolean flag) {
        //先查出所有的一级菜单
        List<HyOpenAreaInfoDO> openArea = hyOpenAreaInfoDAO.queryFirstLevel();
        Map<Long, HyOpenAreaInfoDO> longHyOpenAreaInfoDOMap = openArea.stream().collect(Collectors.toMap(HyOpenAreaInfoDO::getId, x -> x));

        //查询关键字下所有的数据 原始的数据
        List<HyOpenAreaInfoDO> hyOpenAreaInfoDOS = hyOpenAreaInfoDAO.queryByKeyword(keyword,null,areaStatus,flag);
        Set<Long> longSet = hyOpenAreaInfoDOS.stream().map(HyOpenAreaInfoDO::getId).collect(Collectors.toSet());

        List<HyOpenAreaInfoDO> result = new ArrayList<>();
        result.addAll(hyOpenAreaInfoDOS);
        hyOpenAreaInfoDOS.stream().forEach(x->{
            Long parentId = x.getParentId();

            if (parentId!=null&&!longSet.contains(parentId)){
                //添加到集合中
                longSet.add(x.getParentId());
                HyOpenAreaInfoDO hyOpenAreaInfoDO = longHyOpenAreaInfoDOMap.get(parentId);
                result.add(hyOpenAreaInfoDO);
            }
        });

        JSONArray objects = buildTree(JSONArray.parseArray(JSONObject.toJSONString(result)), "id", "parentId","childNode" );
        List<OpenAreaTreeVO> openAreaTreeVOS = JSONObject.parseArray(objects.toJSONString(), OpenAreaTreeVO.class);
        return openAreaTreeVOS;
    }

    @Override
    public List<OpenAreaTreeVO> searchOpenArea(String keyword,Boolean applyFlag, Boolean flag) {
        long startTime = System.currentTimeMillis();
        List<HyOpenAreaInfoDO> allAreaList = hyOpenAreaInfoDAO.getAllOpenArea();
        log.info("11耗时：{}", System.currentTimeMillis() - startTime);
        return OpenAreaTreeVO.convertTree(allAreaList, keyword, applyFlag);
    }


    @Override
    public List<OpenAreaTreeVO> queryAllOpenAreaByKeyword(String keyword,Boolean applyFlag, Boolean flag) {
        long startTime = System.currentTimeMillis();
        //先查出所有的一级菜单
        List<HyOpenAreaInfoDO> openArea = hyOpenAreaInfoDAO.queryFirstLevel();
        log.info("11耗时：{}", System.currentTimeMillis() - startTime);
        Map<Long, HyOpenAreaInfoDO> longHyOpenAreaInfoDOMap = openArea.stream().collect(Collectors.toMap(HyOpenAreaInfoDO::getId, x -> x));

        //查询关键字下所有的数据 原始的数据
        List<HyOpenAreaInfoDO> hyOpenAreaInfoDOS = hyOpenAreaInfoDAO.queryByKeyword(keyword,applyFlag,null,flag);
        log.info("22耗时：{}", System.currentTimeMillis() - startTime);
        Map<Long, HyOpenAreaInfoDO> hyMap = hyOpenAreaInfoDOS.stream().collect(Collectors.toMap(HyOpenAreaInfoDO::getId, x -> x));

        Set list = new HashSet();
        hyOpenAreaInfoDOS.stream().forEach(x->{
            Long parentId = x.getParentId();
            HyOpenAreaInfoDO hyOpenAreaInfoDO = hyMap.get(parentId);
            if (hyOpenAreaInfoDO==null&&parentId!=null){
                //添加到集合中
                list.add(x.getParentId());
            }
        });
        log.info("33耗时：{}", System.currentTimeMillis() - startTime);
        if (CollectionUtils.isNotEmpty(list)){
            //二级采单
            List<HyOpenAreaInfoDO> hyOpenAreaInfoDOList = hyOpenAreaInfoDAO.queryByIdsExcludeFirstLevel(new ArrayList<>(list));
            hyOpenAreaInfoDOS.addAll(hyOpenAreaInfoDOList);
            //如果二级采单是空 说明list全部是一级采单
            if (CollectionUtils.isEmpty(hyOpenAreaInfoDOList)){
                list.stream().forEach(x->{
                    HyOpenAreaInfoDO hyOpenAreaInfoDO = hyMap.get(x);
                    if (hyOpenAreaInfoDO==null){
                        hyOpenAreaInfoDOS.add(longHyOpenAreaInfoDOMap.get(x));
                    }
                });
            }
            hyOpenAreaInfoDOList.stream().forEach(x->{
                Long parentId = x.getParentId();
                HyOpenAreaInfoDO hyOpenAreaInfoDO = hyMap.get(parentId);
                if (hyOpenAreaInfoDO==null){
                    HyOpenAreaInfoDO infoDO = longHyOpenAreaInfoDOMap.get(parentId);
                    hyOpenAreaInfoDOS.add(infoDO);
                }
            });
        }
        log.info("44耗时：{}", System.currentTimeMillis() - startTime);
        JSONArray objects = buildTree(JSONArray.parseArray(JSONObject.toJSONString(hyOpenAreaInfoDOS)), "id", "parentId","childNode" );
        List<OpenAreaTreeVO> openAreaTreeVOS = JSONObject.parseArray(objects.toJSONString(), OpenAreaTreeVO.class);
        log.info("55耗时：{}", System.currentTimeMillis() - startTime);
        return openAreaTreeVOS;
    }


    @Override
    public List<OpenAreaVO> getChildrenList(Long parentId) {
        List<HyOpenAreaInfoDO> childrenList = hyOpenAreaInfoDAO.getChildrenList( parentId);
        List<OpenAreaVO> result = new ArrayList<>();
        childrenList.stream().forEach(x->{
            OpenAreaVO openAreaVO = convertDoToVo(x);
            result.add(openAreaVO);
        });
        return result;
    }

    @Override
    public Boolean batchUpdate(String userId, OpenAreaRequest request) {
        //修改选择的区域
        hyOpenAreaInfoDAO.batchUpdateById(request.getBackgroundBanner(),request.getDetailBanner(),request.getStatus(),userId,request.getIdList());
        //修改选择区域的子区域 子区域不需要更新背景图和详情图
        hyOpenAreaInfoDAO.batchUpdateByParentId(null,null,request.getStatus(),userId,request.getIdList());

        return Boolean.TRUE;
    }

    @Override
    public PageInfo<OpenAreaVO> queryKeyOpenAreaList(Integer pageSize, Integer pageNumber,String keyWord,Integer status) {
        PageHelper.startPage(pageNumber,pageSize);
        List<HyOpenAreaInfoDO> hyOpenAreaInfoDOS = hyOpenAreaInfoDAO.queryKeyOpenArea(keyWord,status);
        PageInfo hyOpenAreaInfoDOPageInfo = new PageInfo<>(hyOpenAreaInfoDOS);
        if (hyOpenAreaInfoDOPageInfo==null){
            return new PageInfo<>();
        }
        List<OpenAreaVO> list = new ArrayList<>();
        List<HyOpenAreaInfoDO> hyOpenAreaInfoDOList = hyOpenAreaInfoDOPageInfo.getList();
        List<String> userIds = hyOpenAreaInfoDOList.stream().map(HyOpenAreaInfoDO::getUpdateUserId).collect(Collectors.toList());
        List<EnterpriseUserDO> userInfoByUserIds = enterpriseUserDAO.getUserInfoByUserIds(userIds);
        Map<String, String> userMap = userInfoByUserIds.stream().collect(Collectors.toMap(EnterpriseUserDO::getUserId, EnterpriseUserDO::getName));
        hyOpenAreaInfoDOList.stream().forEach(x->{
            OpenAreaVO openAreaVO = convertDoToVo(x);
            openAreaVO.setUpdateUserName(userMap.get(x.getUpdateUserId()));
            openAreaVO.setUpdateTime(DateUtils.format(x.getUpdateTime(),DateUtils.DATE_FORMAT_19));
            list.add(openAreaVO);
        });
        hyOpenAreaInfoDOPageInfo.setList(list);
        return hyOpenAreaInfoDOPageInfo;
    }

    @Override
    public PageInfo<OpenAreaVO> franchisableProvinces(Integer pageSize, Integer pageNumber) {
        PageHelper.startPage(pageNumber,pageSize);
        List<HyOpenAreaInfoDO> openArea = hyOpenAreaInfoDAO.queryFirstLevel();
        PageInfo hyOpenAreaInfoDOPageInfo = new PageInfo<>(openArea);
        List<OpenAreaVO> list = new ArrayList<>();
        List<HyOpenAreaInfoDO> hyOpenAreaInfoDOList = hyOpenAreaInfoDOPageInfo.getList();
        hyOpenAreaInfoDOList.stream().forEach(x->{
            list.add(convertDoToVo(x));
        });
        hyOpenAreaInfoDOPageInfo.setList(list);
        return hyOpenAreaInfoDOPageInfo;
    }

    @Override
    public Boolean deleteKeyCity(Long id) {
        HyOpenAreaInfoDO hyOpenAreaInfoDO = hyOpenAreaInfoDAO.selectById(id);
        if (hyOpenAreaInfoDO==null){
            throw  new ServiceException(ErrorCodeEnum.OPEN_AREA_IS_NOT_EXISTS);
        }
        hyOpenAreaInfoDO.setAreaStatus(AreaStatusEnum.OPEN.getCode());
        hyOpenAreaInfoDAO.updateByPrimaryKeySelective(hyOpenAreaInfoDO);
        return Boolean.TRUE;
    }

    @Override
    public Boolean updateKeyCityStatus(Long id, Integer keyOpenStatus) {
        HyOpenAreaInfoDO hyOpenAreaInfoDO = hyOpenAreaInfoDAO.selectById(id);
        if (hyOpenAreaInfoDO==null){
            throw  new ServiceException(ErrorCodeEnum.OPEN_AREA_IS_NOT_EXISTS);
        }
        hyOpenAreaInfoDO.setKeyOpenStatus(keyOpenStatus);
        hyOpenAreaInfoDAO.updateByPrimaryKeySelective(hyOpenAreaInfoDO);
        return Boolean.TRUE;
    }


    @Override
    public Boolean addOpenArea() {
        //查询出所有的市
        List<HyOpenAreaInfoDO> openArea = hyOpenAreaInfoDAO.selectAllCity();
        if (CollectionUtils.isNotEmpty(openArea)){
            //在每个市下面添加名称为不限的区
            openArea.forEach(x->{
                Long id = x.getId();
                HyOpenAreaInfoDO hyOpenAreaInfoDO = new HyOpenAreaInfoDO();
                hyOpenAreaInfoDO.setAreaStatus("open");
                hyOpenAreaInfoDO.setAreaName("不限");
                hyOpenAreaInfoDO.setParentId(id);
                hyOpenAreaInfoDO.setAreaPath(x.getAreaPath()+"不限/");
                hyOpenAreaInfoMapper.insertSelective(hyOpenAreaInfoDO);
            });
        }
        return true;
    }

    private OpenAreaVO convertDoToVo(HyOpenAreaInfoDO hyOpenAreaInfoDO){
        OpenAreaVO openAreaVO = new OpenAreaVO();
        openAreaVO.setId(hyOpenAreaInfoDO.getId());
        openAreaVO.setAreaName(hyOpenAreaInfoDO.getAreaName());
        openAreaVO.setParentId(hyOpenAreaInfoDO.getParentId());
        openAreaVO.setAreaPath(hyOpenAreaInfoDO.getAreaPath());
        openAreaVO.setAreaStatus(hyOpenAreaInfoDO.getAreaStatus());
        openAreaVO.setBackgroundBanner(hyOpenAreaInfoDO.getBackgroundBanner());
        openAreaVO.setDetailBanner(hyOpenAreaInfoDO.getDetailBanner());
        openAreaVO.setKeyOpenStatus(hyOpenAreaInfoDO.getKeyOpenStatus());
        return openAreaVO;
    }


    /**
     * 构建树
     * @param arr
     * @param id
     * @param pid
     * @param child
     * @return
     */
    public static JSONArray buildTree(JSONArray arr, String id, String pid, String child) {
        //新建一个JSONArray来接收组装成树形结构的返回值
        JSONArray jsonArray = new JSONArray();
        //新建一个JSONObject对象
        JSONObject hash = new JSONObject();
        //将数组转换为object格式
        for (int i = 0; i < arr.size(); i++) {
            //获取当前的JSON对象
            JSONObject json = (JSONObject) arr.get(i);
            //把当前id作为键，当前JSON对象作为值 put回hash这个Object对象中
            //这里的put方法类似于map的put方法
            hash.put(json.getString(id), json);
        }
        //遍历结果集
        for (int j = 0; j < arr.size(); j++) {
            //单条记录
            JSONObject aVal = (JSONObject) arr.get(j);
            //在hash中取出key为单条记录中pid的值
            String pidStr = "";
            //如果父级id不等于null
            if (aVal.get(pid) != null) {
                pidStr = aVal.get(pid).toString();
            }
            //从hash这个对象中获取父级对象  parent
            JSONObject hashParent = (JSONObject) hash.get(pidStr);
            //如果记录的pid存在，则说明它有父节点，将她添加到孩子节点的集合中
            if (hashParent != null) {
                //检查是否有child属性
                if (hashParent.get(child) != null) {
                    //有子节点 则先将子节点取出
                    JSONArray children = (JSONArray) hashParent.get(child);
                    //然后把当前这个对象放进子节点之中
                    children.add(aVal);
                    //最后把子节点在放回父节点之中
                    hashParent.put(child, children);
                } else {
                    //无子节点 则新建一个子节点
                    JSONArray children = new JSONArray();
                    //然后再把当前对象放进去
                    children.add(aVal);
                    //最后在放回父节点之中
                    hashParent.put(child, children);
                }
            } else {
                jsonArray.add(aVal);
            }
        }
        return jsonArray;
    }


}
