package com.yeejoin.amos.patrol.business.service.impl;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.amos.patrol.business.constants.XJConstant;
import com.yeejoin.amos.patrol.business.dao.mapper.InputItemMapper;
import com.yeejoin.amos.patrol.business.dao.mapper.PointMapper;
import com.yeejoin.amos.patrol.business.dao.mapper.RouteMapper;
import com.yeejoin.amos.patrol.business.dao.mapper.RoutePointItemMapper;
import com.yeejoin.amos.patrol.business.dao.repository.IInputItemDao;
import com.yeejoin.amos.patrol.business.dao.repository.IPlanDao;
import com.yeejoin.amos.patrol.business.dao.repository.IPointClassifyDao;
import com.yeejoin.amos.patrol.business.dao.repository.IPointDao;
import com.yeejoin.amos.patrol.business.dao.repository.IPointInputItemDao;
import com.yeejoin.amos.patrol.business.dao.repository.IRouteDao;
import com.yeejoin.amos.patrol.business.dao.repository.IRoutePointDao;
import com.yeejoin.amos.patrol.business.dao.repository.IRoutePointItemDao;
import com.yeejoin.amos.patrol.business.param.LoginUserParam;
import com.yeejoin.amos.patrol.business.param.RoutePageParam;
import com.yeejoin.amos.patrol.business.param.SynRouteInfoParam;
import com.yeejoin.amos.patrol.business.param.SynRouteParam;
import com.yeejoin.amos.patrol.business.service.intfc.IPlanService;
import com.yeejoin.amos.patrol.business.service.intfc.IPlanTaskService;
import com.yeejoin.amos.patrol.business.service.intfc.IRouteService;
import com.yeejoin.amos.patrol.business.util.DaoCriteria;
import com.yeejoin.amos.patrol.business.vo.InputItemVo;
import com.yeejoin.amos.patrol.business.vo.PointInputItemVo;
import com.yeejoin.amos.patrol.business.vo.PointVo;
import com.yeejoin.amos.patrol.core.common.request.CommonPageable;
import com.yeejoin.amos.patrol.core.common.request.RoutePointInputItemRequest;
import com.yeejoin.amos.patrol.core.common.response.RoutePointRespone;
import com.yeejoin.amos.patrol.core.enums.QueryOperatorEnum;
import com.yeejoin.amos.patrol.core.util.query.BaseQuerySpecification;
import com.yeejoin.amos.patrol.dao.entity.InputItem;
import com.yeejoin.amos.patrol.dao.entity.Plan;
import com.yeejoin.amos.patrol.dao.entity.Point;
import com.yeejoin.amos.patrol.dao.entity.PointClassify;
import com.yeejoin.amos.patrol.dao.entity.PointInputItem;
import com.yeejoin.amos.patrol.dao.entity.Route;
import com.yeejoin.amos.patrol.dao.entity.RoutePoint;
import com.yeejoin.amos.patrol.dao.entity.RoutePointItem;
import com.yeejoin.amos.patrol.exception.YeeException;
import com.yeejoin.amos.patrol.feign.RemoteSecurityService;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service("routeService")
public class RouteServiceImpl implements IRouteService {

    @Autowired
    private IRouteDao iRouteDao;
    @Autowired
    private IPlanDao planDao;

    @Autowired
    private IRoutePointDao iRoutePointDao;

    @Autowired
    private IPointDao iPointDao;

    @Autowired
    private IPointClassifyDao iPointClassifyDao;

    @Autowired
    private IInputItemDao iInputItemDao;

    @Resource
    private RouteMapper routeMapper;

    @Resource
    private PointMapper pointMapper;

    @Resource
    private InputItemMapper inputItemMapper;

    @Resource
    private RoutePointItemMapper routePointItemMapper;

    @Autowired
    private IPointInputItemDao iPointInputItemDao;

    @Autowired
    private IPlanService planService;

    @Autowired
    private IPlanTaskService planTaskService;

    @Autowired
    private IRoutePointItemDao iRoutePointItemDao;
    @Autowired
    private RemoteSecurityService remoteSecurityService;

    @Override
    @Transactional
    public Route addRoute(Route route) {
        String creatorId = route.getCreatorId();
        String orgCode = route.getOrgCode();
        route = iRouteDao.saveAndFlush(route);
        Long rId = route.getId();
        List<RoutePoint> routePoints = route.getRoutePointList();

        routePoints.forEach(rp -> {
            rp.setOrgCode(orgCode);
            rp.setRouteId(rId);
            rp.setCreatorId(creatorId);
            List<RoutePointItem> routePointItems = rp.getRoutePointItem();
            rp = iRoutePointDao.saveAndFlush(rp);
            Long rpId = rp.getId();
            routePointItems.forEach(rpi -> {
                rpi.setRoutePointId(rpId);
                rpi.setCreatorId(creatorId);
                iRoutePointItemDao.saveAndFlush(rpi);
            });
        });
        return route;
    }

    @Override
    @Transactional
    public void delRouteById(Long[] ids) {
        //0.删除路线
        iRouteDao.delRouteById(Arrays.asList(ids));
        // 1.停用关联计划
        planService.disablePlan(ids);
        // 2.停用关联计划任务
        planTaskService.disablePlanTask(ids);
    }

    @Override
    @Transactional
    public Route updateRoute(Route route) {
        List<RoutePoint> routePoints = route.getRoutePointList();
        route = iRouteDao.saveAndFlush(route);
        Long routeId = route.getId();
        String orgCode = route.getOrgCode();
        String CreatorId = route.getCreatorId();
        routePoints.forEach(rp -> {
            rp.setOrgCode(orgCode);
            rp.setRouteId(routeId);
            rp.setCreatorId(CreatorId);
            if (rp.getIsDelete()) {
                iRoutePointItemDao.delRoutePointItem(rp.getId());
                iRoutePointDao.deleteById(rp.getId());
            } else {
                List<RoutePointItem> routePointItems = rp.getRoutePointItem();
                rp = iRoutePointDao.saveAndFlush(rp);
                Long rpId = rp.getId();
                List<RoutePointItem> delRoutePointItem = new ArrayList<>();
                if (routePointItems != null && !routePointItems.isEmpty()) {
                    routePointItems.forEach(rpi -> {
                        if (rpi.getIsDelete()) {
                            delRoutePointItem.add(rpi);
//                            iRoutePointItemDao.delete(rpi.getId());////
                        } else {
                            rpi.setRoutePointId(rpId);
                            rpi.setCreatorId(CreatorId);
                            if (rpi.getId() == 0) {
                                iRoutePointItemDao.save(rpi);
                            } else {
                                routePointItemMapper.updateRoutePointItem(rpi);
                            }
                        }
                    });
                    if (!delRoutePointItem.isEmpty()) {
                        iRoutePointItemDao.deleteAll(delRoutePointItem);
                    }
                }

            }
        });
        return iRouteDao.save(route);
    }

    @Override
    @Transactional
    public Route updateRouteNew(Route route) {
        List<RoutePoint> routePoints = route.getRoutePointList();
        route = iRouteDao.saveAndFlush(route);
        Long routeId = route.getId();
        String orgCode = route.getOrgCode();
        String CreatorId = route.getCreatorId();
        // 以下删除顺序不可更改
        // 删除旧的项
        routePointItemMapper.delRoutePointItemByRouteId(routeId);
        // 删除旧的点
        iRoutePointDao.delRoutePointByRouteId(routeId);
        // 保存新的点
        if (routePoints != null && !routePoints.isEmpty()) {
            List<RoutePoint> points = new ArrayList<>();
            List<RoutePointItem> items = new ArrayList<>();
            List<Long> pointIds = new ArrayList<>();
            routePoints.forEach(rp -> {
                rp.setOrgCode(orgCode);
                rp.setRouteId(routeId);
                rp.setCreatorId(CreatorId);
                points.add(rp);
                pointIds.add(rp.getPointId());
            });
            List<RoutePoint> savedPoints = iRoutePointDao.saveAll(points);
            List<Map<String, Object>> pointRefItem = pointMapper.getPointRefItem(pointIds);
            if (!savedPoints.isEmpty()) {
                savedPoints.forEach(rp -> {
                    String excludeItems = rp.getExcludeItems();
                    Set<Long> excludeItemIdSet = new HashSet<>();
                    if (excludeItems != null && !excludeItems.isEmpty()) {
                        String[] itemIds = excludeItems.split(",");
                        for (String itemId : itemIds) {
                            try {
                                excludeItemIdSet.add(Long.valueOf(itemId));
                            } catch (Exception e) {
                            }
                        }
                    }
                    final int[] orderNum = {1};
                    pointRefItem.forEach(ref -> {
                        Long pointId = rp.getPointId();
                        if(pointId.equals(ref.get("pointId"))){
                            if(!excludeItemIdSet.contains(ref.get("itemId"))) {
                                RoutePointItem item = new RoutePointItem();
                                item.setPointInputItemId((Long) ref.get("id"));
                                item.setRoutePointId(rp.getId());
                                item.setPointClassifyId(Long.valueOf(ref.get("classifyId").toString()));
                                item.setOrderNo(orderNum[0]++);
                                item.setPointId(pointId);
                                item.setIsDelete(false);
                                items.add(item);
                            }
                        }
                    });
                });
                if(!items.isEmpty()) {
                    iRoutePointItemDao.saveAll(items);
                }
            }
        }

        return route;
    }

    @Override
    @Transactional(rollbackFor = {YeeException.class, Exception.class})
    public void migrateRoutePoint(Long sourceRouteId, Long[] pointIds, Long targetRouteId) {
        List<RoutePoint> routePointList = iRoutePointDao.queryRoutePoint(sourceRouteId, pointIds);
        if (routePointList.isEmpty()) {
            throw new YeeException("点数据不存在");
        }
        List<Long> targetPointIds = iRoutePointDao.findAllByRouteId(targetRouteId);
        List<Long> targetPointDelIds = new ArrayList<>();
        List<Long> ids = new ArrayList<>();
        for (RoutePoint routePoint : routePointList) {
            if (targetPointIds.contains(routePoint.getPointId())) {
                targetPointDelIds.add(routePoint.getPointId());
            }
            ids.add(routePoint.getId());
            routePoint.setRouteId(targetRouteId);
        }
        iRoutePointDao.saveAll(routePointList);
        if (!targetPointDelIds.isEmpty()) {
            iRoutePointDao.deleteByRouteIdAndPointIdInAndIdNotIn(targetRouteId, targetPointDelIds, ids);
        }
    }

    @Override
    public Route queryRouteById(Long id) {
        return iRouteDao.findById(id).get();
    }

    @Override
    public Page<Route> queryRouteInfo(List<DaoCriteria> criterias, CommonPageable commonPageable) {
        BaseQuerySpecification<Route> spec = new BaseQuerySpecification<>(criterias);
        return iRouteDao.findAll(spec, commonPageable);
    }

    @Override
    public Page<Point> queryRoutePoints(Long routeId, List<DaoCriteria> criterias, CommonPageable commonPageable) {
        List<Long> routePointIdList = queryRoutePointIds(routeId);
        if (routePointIdList.size() == 0) {
            return new PageImpl<Point>(new ArrayList<Point>());
        }
        if (criterias == null) {
            criterias = new ArrayList<>();
        }
        for (int i = 0; i < routePointIdList.size(); i++) {
            DaoCriteria criteria = new DaoCriteria();
            criteria.setOperator(QueryOperatorEnum.EQUAL.getName());
            criteria.setPropertyName("id");
            criteria.setValue(routePointIdList.get(i));
            criterias.add(criteria);
        }

        BaseQuerySpecification<Point> spec = new BaseQuerySpecification<>(criterias);
        return iPointDao.findAll(spec, commonPageable);
    }

    @Override
    public Page<RoutePointRespone> queryRoutePoints(Long routeId, HashMap<String, Object> param, CommonPageable commonPageable) {
        param.put("routeId", routeId);
        long total = routeMapper.queryRoutePointsCount(param);
        param.put("offset", commonPageable.getPageNumber() * commonPageable.getPageSize());
        param.put("pageSize", commonPageable.getPageSize());
        List<RoutePointRespone> list = routeMapper.queryRoutePointsByCondition(param);
        Page<RoutePointRespone> page = new PageImpl<RoutePointRespone>(list, commonPageable, total);
        return page;
    }

    @Override
    public int countRoutePoint(Long routeId) {
        int routePointCount = iRoutePointDao.countRoutePoint(routeId);
        return routePointCount;
    }

    @Override
    public List<Long> queryRoutePointIds(Long routeId) {
        return iRoutePointDao.queryRoutePointIds(routeId);
    }

    @Override
    @Transactional
    public void addRoutePoint(List<RoutePoint> routePointList) {
        int size = iRoutePointDao.maxRoutePointOrderNo(routePointList.get(0).getRouteId()) + 1;
        List<RoutePoint> pointList = new ArrayList<>();
        //1.更新点的路线信息
        for (RoutePoint routePoint : routePointList) {
            Long pointId = routePoint.getPointId();
            Long routeId = routePoint.getRouteId();
            routePoint.setOrderNo(size);
            size = size + 1;
            pointList.add(routePoint);
            Point point = iPointDao.findById(pointId).get();
            Route route = iRouteDao.findById(routeId).get();
            String routeIds = point.getRouteId();
            String routeNames = point.getRouteName();
            if (routeIds != null && routeIds != "") {
                String[] routeIdsStr = routeIds.split(",");
                List<String> list = Arrays.asList(routeIdsStr);

                if (!list.contains(String.valueOf(routeId))) {
                    routeIds = routeIds + "," + routeId;
                    routeNames = routeNames + "," + route.getName();
                }
            } else {
                routeIds = String.valueOf(routeId);
                routeNames = route.getName();
            }
            point.setRouteId(routeIds);
            point.setRouteName(routeNames);
        }//end 更新点的路线信息
        iRoutePointDao.saveAll(pointList);
    }

    private void updatePointRouteIdAndName(List<RoutePoint> routePointList) {
        for (RoutePoint routePoint : routePointList) {    //更新点的路线信息
            Long pointId = routePoint.getPointId();
            Long routeId = routePoint.getRouteId();
            Point point = iPointDao.findById(pointId).get();
            Route route = iRouteDao.findById(routeId).get();
            String routeIds = point.getRouteId();
            String routeNames = point.getRouteName();
            if (routeIds != null && routeIds != "") {
                String[] routeIdsStr = routeIds.split(",");
                List<String> list = Arrays.asList(routeIdsStr);

                if (!list.contains(String.valueOf(routeId))) {
                    routeIds = routeIds + "," + routeId;
                    routeNames = routeNames + "," + route.getName();
                }
            } else {
                routeIds = String.valueOf(routeId);
                routeNames = route.getName();
            }
            point.setRouteId(routeIds);
            point.setRouteName(routeNames);
        }//end 更新点的路线信息
    }

    private void detelePointRouteIdAndName(List<RoutePoint> routePointList) {
        for (RoutePoint routePoint : routePointList) {    //更新点的路线信息
            Long pointId = routePoint.getPointId();
            Long routeId = routePoint.getRouteId();
            Point point = iPointDao.findById(pointId).get();
            String routeIds = point.getRouteId();
            String routeNames = point.getRouteName();
            if (routeIds != null && routeIds != "") {
                String[] routeIdsStr = routeIds.split(",");
                List<String> list = new ArrayList<>(routeIdsStr.length);
                Collections.addAll(list, routeIdsStr);
                List<String> nameList = new ArrayList<>();
                Iterator<String> iter = list.iterator();
                while (iter.hasNext()) {
                    String item = iter.next();
                    if (item.equals(String.valueOf(routeId))) {
                        iter.remove();
                    }
                }
                for (String rId : list) {
                    Route route = iRouteDao.findById(Long.parseLong(rId)).get();
                    nameList.add(route.getName());
                }
                routeIds = StringUtils.join(list, ",");
                routeNames = StringUtils.join(nameList, ",");
            }
            point.setRouteId(routeIds);
            point.setRouteName(routeNames);
        }//end 更新点的路线信息
    }

    @Override
    @Transactional
    public void deleteRoutePoint(Long routeId, Long[] pointIds) {
        List<RoutePoint> routePointList = iRoutePointDao.queryRoutePoint(routeId, pointIds);
        for (RoutePoint routePoint : routePointList) {    //更新点的路线信息
            Long pointId = routePoint.getPointId();
            Point point = iPointDao.findById(pointId).get();
            Route route = iRouteDao.findById(routeId).get();
            String routeIds = point.getRouteId();
            String routeNames = point.getRouteName();
            if (null != routeIds && "" != routeIds) {
                String[] routeIdsStr = routeIds.split(",");
                String[] routeNameStr = routeNames.split(",");
                List<String> idList = new ArrayList<String>(routeIdsStr.length);
                Collections.addAll(idList, routeIdsStr);
                List<String> nameList = new ArrayList<String>(routeNameStr.length);
                Collections.addAll(nameList, routeNameStr);
                if (idList.contains(String.valueOf(routeId))) {
                    idList.remove(String.valueOf(routeId));
                    nameList.remove(route.getName());
                }
                routeIds = StringUtils.join(idList.toArray(), ",");
                routeNames = StringUtils.join(nameList.toArray(), ",");
            }
            point.setRouteId(routeIds);
            point.setRouteName(routeNames);
            iRoutePointDao.deleteById(routePoint.getId());
        }
    }


    @Override
    public List<PointInputItemVo> listRoutePointInputItem(Long routeId, Long pointId) {
        List<PointInputItemVo> inputItemList = routeMapper.getInputItemById(routeId, pointId);
        return inputItemList;
    }

    @Override
    @Transactional
    public void updateRoutePointInputItem(Long routeId, Long pointId, Long[] inputItemIds) {
        Long[] pointIds = {pointId};
        String creatorId = "";
        long routePointId = 0;
        RoutePoint routePoint = null;
        // 1.先查找并删除表中已有的行（旧的项）
        List<RoutePoint> oldRoutePointList = iRoutePointDao.queryRoutePoint(routeId, pointIds);
        if (oldRoutePointList.size() > 0) {
            routePoint = oldRoutePointList.get(0);

            creatorId = routePoint.getCreatorId();
            routePointId = routePoint.getId();
        }
        iRoutePointItemDao.delRoutePointItem(routePointId);

        // 2.保存新的项到数据库
        List<RoutePointItem> routePointList = new ArrayList<>();
        int orderNo = 0;
        for (Long inputItemId : inputItemIds) {
            PointInputItem pointInputItem = iPointInputItemDao.getPointInputItem(pointId, inputItemId);
            RoutePointItem routePointItem = new RoutePointItem();
            routePointItem.setCreatorId(creatorId);
            routePointItem.setOrderNo(orderNo++);
            routePointItem.setPointInputItemId(pointInputItem.getId());
            routePointItem.setRoutePointId(routePointId);
            routePointItem.setRoutePoint(routePoint);

            routePointList.add(routePointItem);
        }
        iRoutePointItemDao.saveAll(routePointList);
    }

    @Override
    public List<Route> queryRouteInfo(List<DaoCriteria> criterias) {
        BaseQuerySpecification<Route> spec = new BaseQuerySpecification<>(criterias);
        return iRouteDao.findAll(spec);
    }

    @Override
    public Map<String, List<InputItem>> listRoutePointInputItemWithClassify(Long routeId, Long pointId) {
        Map<String, List<InputItem>> classifyInputItemMap = new HashMap<>();
        List<PointInputItem> pointInputItemList = routeMapper.getRoutePointInputItem(routeId, pointId);        // 路线点项列表
        List<PointClassify> pointClassifyList = iPointClassifyDao.getPointClassifyByPointId(pointId);    //点分类列表

        for (PointClassify pointClassify : pointClassifyList) {
            List<InputItem> inputItemList = new ArrayList<>();
            for (PointInputItem pointInputItem : pointInputItemList) {
                if (pointInputItem.getClassifyIds().contains(String.valueOf(pointClassify.getId()))) {
                    inputItemList.add(iInputItemDao.findById(pointInputItem.getInputItemId()).get());
                }
            }
            classifyInputItemMap.put(pointClassify.getName(), inputItemList);
        }
        return classifyInputItemMap;
    }

    @Override
    public Page<HashMap<String, Object>> getRouteInfo(String toke, String product, String appKey, RoutePageParam params) {
        long total = routeMapper.countRoute(params);
        List<HashMap<String, Object>> content = routeMapper.getRouteInfo(params);
        Page<HashMap<String, Object>> result = new PageImpl<HashMap<String, Object>>(content, params, total);
        return result;
    }

    @Override
    public List<Plan> queryPlanByRouteId(long routeId) {
        List<Plan> list = planDao.queryPlanByRouteId(routeId, XJConstant.PLAN_STATUS_START);
        return list;
    }

    @Override
    public List<HashMap<String, Object>> queryRouteListByOrgCode(String orgCode, String userId, String deptId) {
        return routeMapper.queryRouteListByOrgCode(orgCode, userId, deptId);
    }

    @Override
    public void exchangeRoutePointOrderNumber(long src, long target) {
        List<Long> ids = new ArrayList<>();
        ids.add(src);
        ids.add(target);
        List<RoutePoint> points = iRoutePointDao.findAllById(ids);
        int srcNo = points.get(0).getOrderNo();
        int targetNo = points.get(1).getOrderNo();
        points.get(0).setOrderNo(targetNo);
        points.get(1).setOrderNo(srcNo);
        iRoutePointDao.saveAll(points);
    }

    @Override
    public List<Long> getPointIDByRouyeId(Long routeID) {
        List<Long> list = iRoutePointDao.queryRoutePointIds(routeID);
        return list;
    }

    @Override
    public LinkedHashMap<String, Object> getPointIdByRouteId(List<String> routeIds) {
        LinkedHashMap<String, Object> routePointIdMap = new LinkedHashMap<>();
        for (String routeId : routeIds) {
            List<String> pointIDS = iRoutePointDao.getRoutePointIds(routeId);
//			List<String> pointIds = new ArrayList<>();
//			for (Long pointId : pointIDS) {
//				pointIds.add(pointId.toString());
//			}
            routePointIdMap.put(routeId.toString(), pointIDS);
        }
        return routePointIdMap;
    }

    @Override
    public HashMap<String, Object> listRoutePointInputItem(RoutePointInputItemRequest request) {
        List<PointClassify> pointClassify = iPointClassifyDao.getPointClassifyByPointId(request.getPointId());
        List<HashMap<String, Object>> inputItemList = routeMapper.queryRoutePointItemByCondition(request);
        HashMap<String, Object> result = new HashMap<>();
        result.put("pointClassifyList", pointClassify);
        result.put("routePointItem", inputItemList);
        return result;
    }

    @Override
    public boolean existRouteName(String orgCode, String name) {
        long count = iRouteDao.countAllByOrgCodeAndName(orgCode, name);
        if (count > 0) {
            return true;
        }
        return false;
    }

    @Override
    public List<Route> queryRouteList(String orgCode) {
        // TODO Auto-generated method stub
        return routeMapper.queryRoutesByOrgCode(orgCode);
    }
}
