/*
 *  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.businessdata.service.impl;

import com.youchain.basicdata.domain.Point;
import com.youchain.basicdata.domain.Stock;
import com.youchain.businessdata.domain.*;
import com.youchain.businessdata.service.*;
import com.youchain.utils.*;
import lombok.RequiredArgsConstructor;
import com.youchain.businessdata.repository.AgvTaskRepository;
import com.youchain.businessdata.service.dto.AgvTaskDto;
import com.youchain.businessdata.service.dto.AgvTaskQueryCriteria;
import com.youchain.businessdata.service.mapstruct.AgvTaskMapper;
import lombok.extern.slf4j.Slf4j;
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.servlet.http.HttpServletResponse;


/**
 * @author baobinglin
 * @website https://eladmin.vip
 * @description 服务实现
 * @date 2023-08-18
 **/
@Service
@RequiredArgsConstructor
@Slf4j
public class AgvTaskServiceImpl implements AgvTaskService {

    private final AgvTaskRepository agvTaskRepository;
    private final AgvTaskMapper agvTaskMapper;
    private final EntityManager entityMapper;

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

    @Override
    public List<AgvTaskDto> queryAll(AgvTaskQueryCriteria criteria) {
        return agvTaskMapper.toDto(agvTaskRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    public AgvTask findById(Long id) {
        return agvTaskRepository.findById(id).orElseGet(AgvTask::new);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AgvTaskDto create(AgvTask resources) {
        return agvTaskMapper.toDto(agvTaskRepository.save(resources));
    }

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

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

    @Override
    public void download(List<AgvTaskDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (AgvTaskDto agvTask : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("容器码", agvTask.getStockCode());
            map.put("容器类型", agvTask.getStockTypeCode());
            map.put("起点位置", agvTask.getStartSlotCode());
            map.put("终点位置", agvTask.getEndSlotCode());
            map.put("容器当前位置", agvTask.getSlotCode());
            map.put("任务状态", agvTask.getStatus());
            map.put("任务类型", agvTask.getType());
            map.put("下游任务号", agvTask.getJobId());
            map.put("工作类型", agvTask.getJobType());
            map.put("优先级", agvTask.getJobPriority());
            map.put("强制优先级", agvTask.getJobPriorityType());
            map.put("任务组", agvTask.getJobForce());
            map.put("任务组执行顺序", agvTask.getJobForceAsc());
            map.put("返回报文", agvTask.getJobMessage());
            map.put("变动时间", agvTask.getJobMessageTime());
            map.put("创建时间", agvTask.getCreateTime());
            map.put("开始时间", agvTask.getStartTime());
            map.put("完成时间", agvTask.getEndTime());
            map.put("创建人", agvTask.getCreateBy());
            map.put("修改人", agvTask.getUpdateBy());
            map.put("修改时间", agvTask.getUpdateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AgvTask createAgvTask(String bizStatus, Stock stock, String srcPointCode, String endPointCode, String jobType) {
        AgvTask agvTask = new AgvTask();
        agvTask.setType(bizStatus);
        agvTask.setStockCode(stock == null ? null : stock.getCode());
        agvTask.setStartSlotCode(srcPointCode);
        agvTask.setEndSlotCode(endPointCode);
        agvTask.setStatus(BizStatus.OPEN);
        agvTask.setJobType(jobType);
        agvTaskRepository.save(agvTask);
        return agvTask;
    }

    @Override
    public List<AgvTask> findRepeat(String stockCode, String srcPointCode, String endPointCode) {
        return agvTaskRepository.findRepeat(stockCode, srcPointCode, endPointCode);
    }

    @Override
    public Boolean findByStartSlotCode(String startSlotCode, String type, String jobType) {
        String hql = " from AgvTask agv " +
                " where  agv.startSlotCode='" + startSlotCode + "' " +
                " and agv.type='" + type + "' " +
                " and agv.jobType='" + jobType + "' " +
                " and agv.status in ('OPEN','ATCALL','UP_CONTAINER') ";
        Query query = entityMapper.createQuery(hql);
        List<AgvTask> agvTaskList = query.getResultList();
        return agvTaskList.isEmpty();
    }

    @Override
    public Boolean findByEndSlotCode(String endSlotCode, String type, String jobType) {
        String hql = " from AgvTask agv " +
                " where  agv.endSlotCode='" + endSlotCode + "' " +
                " and agv.type='" + type + "' " +
                " and agv.jobType='" + jobType + "' " +
                " and agv.status in ('OPEN','ATCALL','UP_CONTAINER') ";
        Query query = entityMapper.createQuery(hql);
        List<AgvTask> agvTaskList = query.getResultList();
        return agvTaskList.isEmpty();
    }

    @Override
    public Boolean isByFxEndSlotCode(String endSlotCode, String type, String jobType) {
        String hql = "select COUNT(agv.id) from AgvTask agv " +
                " where  agv.endSlotCode='" + endSlotCode + "' " +
                " and agv.type='" + type + "' " +
                " and agv.jobType='" + jobType + "' " +
                " and agv.status not in ('OPEN','FINISH','CANCEL') ";
        Query query = entityMapper.createQuery(hql);
        Long count = (Long) query.getSingleResult();
        return count<2;
    }

    @Override
    public Boolean findByCcEndSlotCode(String endSlotCode, String type, String jobType) {
        String hql = " from AgvTask agv " +
                " where  agv.endSlotCode='" + endSlotCode + "' " +
                " and agv.type='" + type + "' " +
                " and agv.jobType='" + jobType + "' " +
                " and agv.status in ('ATCALL','UP_CONTAINER') ";
        Query query = entityMapper.createQuery(hql);
        List<AgvTask> agvTaskList = query.getResultList();
        return agvTaskList.isEmpty();
    }

    @Override
    public List<AgvTask> findOpenByAgvTask(String type) {
        return agvTaskRepository.findOpenByAgvTask(type);
    }

    @Override
    public int existsBySrcPoint(Long agvTaskId, String srcPointCode) {
        return agvTaskRepository.existsBySrcPoint(agvTaskId, srcPointCode);
    }

    @Override
    public List<AgvTask> findByStatus(String status) {
        return agvTaskRepository.findByStatus(status);
    }



    @Override
    public Map<String, Object> queryWeeklyTaskCounts() {
        List<Object[]> objectList = agvTaskRepository.queryWeeklyTaskCounts();

        // 使用Stream API直接生成xAxis和series
        List<String> xAxis = objectList.stream()
                .map(obj -> obj[0].toString())
                .collect(Collectors.toList());

        List<Object> series = objectList.stream()
                .map(obj -> obj[1])
                .collect(Collectors.toList());

        // 构建最终的返回数据
        Map<String, Object> data = new HashMap<>();
        data.put("xAxis", xAxis);
        data.put("series", series);
        return data;


    }


    public boolean isEndPointAvailable(String endPointCode, String type, String jobType) {
        return findByEndSlotCode(endPointCode, type, jobType);
    }


    public boolean isSrcPointAvailable(String startSlotCode, String type, String jobType) {
        return findByStartSlotCode(startSlotCode, type, jobType);
    }

}
