/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.youchain.basicdata.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.youchain.appupdate.ReturnJson.RLocLayout;
import com.youchain.basicdata.domain.Area;
import com.youchain.basicdata.domain.Item;
import com.youchain.basicdata.domain.Point;
import com.youchain.basicdata.service.dto.StockSmallDto;
import com.youchain.businessdata.ReturnJson.RPTaskList;
import com.youchain.businessdata.inputJson.IPTask;
import com.youchain.utils.*;
import jdk.internal.dynalink.beans.StaticClass;
import lombok.RequiredArgsConstructor;
import com.youchain.basicdata.repository.PointRepository;
import com.youchain.basicdata.service.PointService;
import com.youchain.basicdata.service.dto.PointDto;
import com.youchain.basicdata.service.dto.PointSmallDto;
import com.youchain.basicdata.service.dto.PointQueryCriteria;
import com.youchain.basicdata.service.mapstruct.PointMapper;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.JsonUtil;
import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.transform.AliasToEntityMapResultTransformer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.*;
import java.io.IOException;
import java.util.stream.Collectors;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletResponse;

/**
 * @author liuxue
 * @website https://eladmin.vip
 * @description 服务实现
 * @date 2023-07-26
 **/
@Service
@RequiredArgsConstructor
@Slf4j
public class PointServiceImpl implements PointService {

    private final PointRepository pointRepository;
    private final PointMapper pointMapper;
    private final EntityManager entityMapper;

    @Override
    public Map<String, Object> queryAll(PointQueryCriteria criteria, Pageable pageable) {
        Page<Point> page = pointRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        return PageUtil.toPage(page.map(pointMapper::toDto));
    }

    @Override
    public List<PointDto> queryAll(PointQueryCriteria criteria) {
        return pointMapper.toDto(pointRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    public List<PointSmallDto> queryKyPointList() {
        List<Map<String, String>> maps = pointRepository.getKyPointList();
        String irsStr = JSON.toJSONString(maps);
        List<PointSmallDto> evaUserResps = JSON.parseArray(irsStr, PointSmallDto.class);
        return evaUserResps;
    }

    @Override
    public List<Point> getPoint(String type, String areaCode, int page, int pageSize) {
        String hql = " from Point p where p.enabled=true and p.status='FREE' and  p.type='" + type + "' ";
        if (areaCode != null) {
            hql += " and p.area.code='" + areaCode + "'";
        }
        Query query = entityMapper.createQuery(hql);
        query.setFirstResult((page - 1) * pageSize);//当前
        query.setMaxResults(pageSize); // 每页的大小
        List<Point> pointList = query.getResultList();
        return pointList;
    }


    @Override
    @Transactional
    public PointDto findById(Long id) {
        Point point = pointRepository.findById(id).orElseGet(Point::new);
        ValidationUtil.isNull(point.getId(), "Point", "id", id);
        return pointMapper.toDto(point);
    }

    @Override
    @Transactional
    public Point findEntityById(Long id) {
        Point point = pointRepository.findById(id).orElseGet(Point::new);
        ValidationUtil.isNull(point.getId(), "Point", "id", id);
        return point;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PointDto create(Point resources) {
        return pointMapper.toDto(pointRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Point resources) {
        Point point = pointRepository.findById(resources.getId()).orElseGet(Point::new);
        ValidationUtil.isNull(point.getId(), "Point", "id", resources.getId());
        point.copy(resources);
        pointRepository.save(point);
    }

    @Override
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            pointRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<PointDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (PointDto point : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("RCS代码", point.getCode());
            map.put("名称", point.getName());
            map.put("状态", point.getStatus());
            map.put("描述", point.getDescription());
            map.put("区域编码", point.getBeatCode());
            map.put("物料编码", point.getItemCode());
            map.put("库区名称", point.getArea().getName());
            map.put("是否启用", point.getEnabled());
            map.put("仓库名称", point.getDept().getName());
            map.put("坐标X", point.getPosX());
            map.put("坐标Y", point.getPosY());
            map.put("坐标Z", point.getPosZ());
            map.put("层", point.getRows());
            map.put("列", point.getCol());
            map.put("排", point.getLine());
            map.put("类型", point.getType());
            map.put("热度", point.getHeat());
            map.put("创建人", point.getCreateBy());
            map.put("修改人", point.getUpdateBy());
            map.put("创建时间", point.getCreateTime());
            map.put("修改时间", point.getUpdateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public Point toEntity(PointDto pointDto) {
        return pointMapper.toEntity(pointDto);
    }

    @Override
    public void queryPoint(String pointCode) {
        /*  String resultJson= HttpPostUtil.sendPostReq(UrlApi.agv_url, jsonObject.toString());//返回ResponseJson*/
        String resultJson = "{\n" +
                "\"status\":200,\n" +
                "\"message\":\"\",\n" +
                "\"data\":[{\n" +
                "\"pointCode\":\"xxxxxx\",\n" +
                "\"pointStatus\":0\n" +
                "}]\n" +
                "}";
        JSONObject resulObject = JSON.parseObject(resultJson);
        String code = resulObject.getString("status") == null ? "" : resulObject.getString("status");
        if (code.equals("200")) {


        }
    }

    @Override
    public List<Point> getPoint(String type, String areaCode) {
        String hql = " from Point p where p.enabled=true and p.status='FREE' and  p.type='" + type + "' ";
        if (areaCode != null) {
            hql += " and p.area.code='" + areaCode + "'";
        }
        Query query = entityMapper.createQuery(hql);
        List<Point> pointList = query.getResultList();
        return pointList;
    }

    @Override
    public Point findByCode(String code, String status, String type, String areaName, String goodType,Double itemHeight) {
        StringBuilder hql = new StringBuilder("from Point point where point.enabled = true");
        Map<String, Object> params = new HashMap<>();
        if (code != null && !code.isEmpty()) {
            hql.append(" and point.code = :code");
            params.put("code", code);
        }
        if (status != null && !status.isEmpty()) {
            hql.append(" and point.status = :status");
            params.put("status", status);
        }
        if (type != null && !type.isEmpty()) {
            hql.append(" and point.type = :type");
            params.put("type", type);
        }
        if (goodType != null && !goodType.isEmpty()) {
            hql.append(" and point.description = :goodType");
            params.put("goodType", goodType);
        }
        if (areaName != null && !areaName.isEmpty()) {
            hql.append(" and point.area.name = :areaName");
            params.put("areaName", areaName);
        }
        if(itemHeight!= null ){
            hql.append(" and point.itemHeight = :itemHeight");
            params.put("itemHeight", itemHeight);
        }
        Query query = entityMapper.createQuery(hql.toString());
        params.forEach(query::setParameter);
        Optional<Point> pointList = query.getResultStream().findFirst();
        return pointList.isPresent() ? pointList.get() : null;
    }

    @Override
    public Point getPoint(String code, String status, String type, String areaName) {
        StringBuilder hql = new StringBuilder("from Point point where point.enabled = true");

        Map<String, Object> parameters = new HashMap<>();

        if (StringUtils.isNotBlank(code)) {
            hql.append(" and point.code = :code");
            parameters.put("code", code);
        }
        if (StringUtils.isNotBlank(status)) {
            hql.append(" and point.status = :status");
            parameters.put("status", status);
        }
        if (StringUtils.isNotBlank(type)) {
            hql.append(" and point.type = :type");
            parameters.put("type", type);
        }
        if (StringUtils.isNotBlank(areaName)) {
            hql.append(" and point.area.name = :areaName");
            parameters.put("areaName", areaName);
        }

        Query query = entityMapper.createQuery(hql.toString());
        parameters.forEach(query::setParameter);

        List<Point> pointList = query.getResultList();
        return pointList.isEmpty() ? null : pointList.get(0);
    }

    @Override
    public Map<String, Point> findByCodes(Set pointCodes) {
        String hql = " from Point where code in (:pointCodes)";
        Query query = entityMapper.createQuery(hql);
        query.setParameter("pointCodes", pointCodes);
        List<Point> pointList = query.getResultList();
        Map<String, Point> pointMap = new HashMap<>();
        for (Point point : pointList) {
            pointMap.put(point.getCode(), point);
        }
        return pointMap;
    }

    @Override
    public List<Point> getPointByBeat_code(String beat_code) {
        String hql = " from Point point where point.beatCode='" + beat_code + "' ";
        Query query = entityMapper.createQuery(hql);
        List<Point> pointList = query.getResultList();
        return pointList;

    }

    public List<Object[]> queryPointKmd() {
        List<Object[]> pointList = null;
        String hql = "select p.area.name,p.status,count(p.status) from Point p where p.area.name in " +
                "('" + AreaNameDic.DJQ + "','" + AreaNameDic.XJQ + "')" +
                " group by p.area.name,p.status order by p.area.name";
        Query query = entityMapper.createQuery(hql);
        pointList = query.getResultList();

        return pointList;
    }

    public List<Object[]> getPointMinxy(String zoneType) {
        List<Object[]> pointList = null;
        String hql = "select min(p.posX),min(p.posY) ,max(p.posX),max(p.posY) from Point p where 1=1 and p.posX>0 and p.posY>0";
        if (zoneType.equals("QHT")) {
            hql += " and p.area.name in ('" + AreaNameDic.DJQ + "','" + AreaNameDic.XJQ + "')";
        }
        Query query = entityMapper.createQuery(hql);
        pointList = query.getResultList();

        return pointList;
    }

    public int getPointCoutType(String itemType) {
        String hql = "select count(p.id) from Point p where 1=1 ";
        if (itemType.equals("前桶440") || itemType.equals("前桶480")) {
            hql += " and p.area.name='" + AreaNameDic.DJQ + "' and p.description='" + itemType + "'";
        } else if (itemType.equals("KC")) {
            hql = " select count(p.id) from Point p where p.area.id=27 ";//前后桶空车区空车数量
        } else {
            hql += " and p.area.name='" + AreaNameDic.XJQ + "' and (p.description is null or p.description ='')";
        }
        Query query = entityMapper.createQuery(hql);
        return Integer.parseInt(query.getResultList().get(0).toString());
    }

    @Transactional(readOnly = true)
    public int getInvCoutType(String itemType) {
        String sql = "select count(inv.id)" +
                " from data_inventory inv " +
                "LEFT JOIN data_item_key ik on ik.id=inv.item_key_id\n" +
                "left join base_item it on it.id=ik.item_id\n" +
                "where 1=1 and inv.quantity>0 and it.good_type='" + itemType + "'";
        if (itemType.equals("KC")) {
            sql = "select count(id) from base_point where area_id=27 and status='USED'";//前后桶空车区空车数量
        }
        List ts = entityMapper.createNativeQuery(sql).getResultList();
        return Integer.parseInt(ts.get(0).toString());
    }

    @Transactional(readOnly = true)
    public String getInvCoutInfo2(String itemType) {
        String sql = "select CONCAT(count(inv.id),'车  ',sum(inv.quantity),'个')" +
                " from data_inventory inv " +
                "LEFT JOIN data_item_key ik on ik.id=inv.item_key_id\n" +
                "left join base_item it on it.id=ik.item_id\n" +
                "where 1=1 and inv.quantity>0 and it.good_type='" + itemType + "'";

        Object t = entityMapper.createNativeQuery(sql).getSingleResult();
//        log.info(sql+"===="+ts.get(0).toString()+"==="+ts.size());
//        for(int i=0;i<ts.size();i++){
//            log.info(ts.get(i).toString());
//        }
        return JsonUtil.toJson(t);
    }

    @Transactional(readOnly = true)
    public String getInvCoutInfo(String itemType) {
        String sql = "select count(inv.id),CAST(sum(inv.quantity) AS SIGNED) " +
                " from data_inventory inv " +
                "LEFT JOIN data_item_key ik on ik.id=inv.item_key_id\n" +
                "left join base_item it on it.id=ik.item_id\n" +
                "where 1=1 and inv.quantity>0 and it.good_type='" + itemType + "'";
        if (itemType.equals("KC")) {
            sql = "select count(id) from base_point where area_id=27 AND status='USED'";//前后桶空车区空车数量
            List ts = entityMapper.createNativeQuery(sql).getResultList();
            return ts.get(0).toString();
        } else {
            List<Object[]> ts = entityMapper.createNativeQuery(sql).getResultList();
            Object[] obj = ts.get(0);
            return obj[0].toString() + "车  " + obj[1].toString();
        }
    }


    @Transactional(readOnly = true)
    public List<RLocLayout> queryLayout(String zoneType, int minx, int miny) {
        String sql = "select  p.code id,inv.point_id,z.name,p.`status`,SUBSTRING(p.code, -6) code,it.good_type itemType,it.code itemName,\n" +
                "p.pos_x x,p.pos_y y," +
                "case when z.`name`= '前后桶空车区'  and p.`status`='USED'  then 3 when p.enabled=0 then '2' when p.`status`='USED' and inv.point_id>0 then '1' else '0'  end type\n" +
                " from base_point p\n" +
                "left join data_inventory inv on inv.point_id=p.id and inv.quantity>0\n" +
                "left join base_area z on z.id=p.area_id\n" +
                "LEFT JOIN data_item_key ik on ik.id=inv.item_key_id\n" +
                "left join base_item it on it.id=ik.item_id\n" +
                "where 1=1 and p.pos_x>0 and p.pos_y>0";
        if (zoneType.equals("QHT")) {
            sql += " and z.`name` in ('" + AreaNameDic.DJQ + "','" + AreaNameDic.XJQ + "')";
        }
        sql += " order by p.pos_x,p.pos_y";
        List ts = entityMapper.createNativeQuery(sql)
                .unwrap(SQLQuery.class)
                .setResultTransformer(
                        AliasToEntityMapResultTransformer.INSTANCE
                )
                .list();
        List<RLocLayout> l = JSON.parseArray(JSON.toJSONString(ts), RLocLayout.class);
        return l;
    }

    @Transactional(readOnly = true)
    public List<Object[]> getZcJxb() {
        String sql = "SELECT SUBSTRING(p.code,8,4) jxb ,CAST(SUBSTRING(p.code,10,2) AS SIGNED) xh,p1.code code1,p2.code code2,p1.`status` status1,p2.`status` status2,p1.item_code item_code1,p2.item_code item_code2,p1.pos_x,p1.pos_y\n" +
                "FROM `base_point` p \n" +
                "left join base_point p1 on p1.code=CONCAT(SUBSTRING(p.code,1,11),'-01')\n" +
                "left join base_point p2 on p2.code=CONCAT(SUBSTRING(p.code,1,11),'-02')\n" +
                "where p.area_id=31 and p.pos_x>0 and p.pos_y>0\n" +
                "GROUP BY SUBSTRING(p.code,8,4)";
        List<Object[]> ts = entityMapper.createNativeQuery(sql).getResultList();
        return ts;
    }

}
