/*
 *  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 cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.youchain.Netty.NettyUtils;
import com.youchain.basicdata.domain.Box;
import com.youchain.basicdata.domain.Item;
import com.youchain.basicdata.domain.Point;
import com.youchain.basicdata.domain.Stock;
import com.youchain.basicdata.service.ItemService;
import com.youchain.basicdata.service.PointService;
import com.youchain.basicdata.service.StockService;
import com.youchain.basicdata.service.dto.ItemDto;
import com.youchain.basicdata.service.dto.PointDto;
import com.youchain.businessdata.domain.*;
import com.youchain.businessdata.service.*;
import com.youchain.exception.handler.ApiResult;
import com.youchain.modules.system.repository.DictRepository;
import com.youchain.modules.system.service.DictService;
import com.youchain.modules.system.service.dto.DictDto;
import com.youchain.modules.system.service.dto.DictQueryCriteria;
import com.youchain.utils.*;
import lombok.RequiredArgsConstructor;
import com.youchain.basicdata.repository.BoxRepository;
import com.youchain.basicdata.service.BoxService;
import com.youchain.basicdata.service.dto.BoxDto;
import com.youchain.basicdata.service.dto.BoxQueryCriteria;
import com.youchain.basicdata.service.mapstruct.BoxMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.sql.Timestamp;
import java.util.*;
import java.io.IOException;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.servlet.http.HttpServletResponse;

import static org.springframework.http.HttpStatus.BAD_REQUEST;

/**
 * @author huojin
 * @website https://eladmin.vip
 * @description 服务实现
 * @date 2023-08-17
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class BoxServiceImpl implements BoxService {

    private final BoxRepository boxRepository;
    private final BoxMapper boxMapper;
    private final EntityManager entityManager;
    private final PointService pointService;
    private final StockService stockService;
    private final ItemService itemService;
    private final AsnDetailService asnDetailService;
    private final ItemKeyService itemKeyService;
    private final AgvTaskService agvTaskService;
    private final TaskService taskService;
    private final InventoryService inventoryService;
    private final PickDetailService pickDetailService;
    private final DictRepository dictRepository;
    private final RedisUtils redisUtils;
    private final DictService dictService;

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

    @Override
    public List<BoxDto> queryAll(BoxQueryCriteria criteria) {
        return boxMapper.toDto(boxRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    @Transactional
    public BoxDto findById(Long id) {
        Box box = boxRepository.findById(id).orElseGet(Box::new);
        ValidationUtil.isNull(box.getId(), "Box", "id", id);
        return boxMapper.toDto(box);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BoxDto create(Box resources) {
        return boxMapper.toDto(boxRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Box resources) {
        redisUtils.del("ButtonBoxCode");
        //判断那个按钮盒
        if (resources.getLampCode() != null && resources.getLampCode().length() > 0) {
            switch (resources.getLampCode()) {
                case "0001":
                    this.executeLampStatus(resources.getLampStatus(), resources.getIP(), NettyUtils.light_1);
                    break;
                case "0002":
                    this.executeLampStatus(resources.getLampStatus(), resources.getIP(), NettyUtils.light_2);
                    break;
                case "0003":
                    this.executeLampStatus(resources.getLampStatus(), resources.getIP(), NettyUtils.light_3);
                    break;
                case "0004":
                    this.executeLampStatus(resources.getLampStatus(), resources.getIP(), NettyUtils.light_4);
                    break;
                default:
                    log.error("{}:按钮盒编码【{}】出错", resources.getCode(), resources.getLampCode());
                    return;
            }
        }

        //根据IP和按钮盒编号查询是否存在了，存在提示，不存在绑定
        if ((resources.getIP() != null && resources.getIP().length() > 0) && (resources.getLampCode() != null && resources.getLampCode().length() > 0)) {
            String hql = " from Box box where box.iP='" + resources.getIP() + "' and box.lampCode='" + resources.getLampCode() + "' and box.id!=" + resources.getId() + " ";
            Query query = entityManager.createQuery(hql);
            List<Box> boxList = query.getResultList();
            if (boxList.size() > 0) {
                StringBuffer sbf = new StringBuffer();
                for (Box box : boxList) {
                    sbf.append(box.getLampCode()).append(",").toString();
                }
                throw new RuntimeException("按钮盒编号" + sbf.deleteCharAt(sbf.length() - 1) + "已绑定!");
            }
        }
        Box box = boxRepository.findById(resources.getId()).orElseGet(Box::new);
        ValidationUtil.isNull(box.getId(), "Box", "id", resources.getId());
        box.copy(resources);
        boxRepository.save(box);


    }

    /**
     * 亮对应的灯
     *
     * @param lamp_status 指示灯状态 ->灯光熄灭 light_off、灯光常亮 light_on、灯光快闪 light_on_fast_flicker、
     *                    灯光慢闪 light_on_slow_flicker、按钮释放 button_off
     * @param ip          ip地址
     * @param index       对应的盒子
     * @return
     */
    public Boolean executeLampStatus(String lamp_status, String ip, String index) {
        switch (lamp_status) {
            case "0":
                NettyUtils.light_off(ip, index, null);
                break;
            case "1":
                NettyUtils.light_on(ip, index, null);
                break;
            case "2":
                NettyUtils.light_on_fast_flicker(ip, index, null);
                break;
            case "3":
                NettyUtils.light_on_slow_flicker(ip, index, null);
                break;
            default:
                log.error("按钮盒状态修改错误:0~3");
                return false;
        }
        return true;
    }

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

    @Override
    public void download(List<BoxDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (BoxDto box : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("物料ID", box.getItem());
            map.put("点位ID", box.getPoint());
//            map.put("IP", box.getIP());
//            map.put("指示灯状态", box.getLampStatus());
//            map.put("按钮盒编号",box.getLampCode());
            map.put("创建人", box.getCreateBy());
            map.put("修改人", box.getUpdateBy());
            map.put("创建时间", box.getCreateTime());
            map.put("修改时间", box.getUpdateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public Box toEntity(BoxDto boxDto) {
        return boxMapper.toEntity(boxDto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized void callBox(BoxDto boxDto) throws RuntimeException {

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Task createTask(Item item, Stock stock, Point endPoint) {
        AsnDetail asnDetail = new AsnDetail();
        asnDetail.setItem(item);
        asnDetail.setLineNo(1l);
        asnDetail.setStatus(BizStatus.OPEN);
        asnDetail.setOrderQty(item.getExtendD1());
        asnDetail.setDept(item.getDept());
        Date date = cn.hutool.core.date.DateUtil.date();
        String propC1 = DateUtil.format(date, "yyyyMMdd");
        asnDetail.setPropC1(propC1);
        asnDetailService.create(asnDetail);

        //生成Itemkey
        ItemKey itemKey = itemKeyService.getItemKey(item, asnDetail.getPropC1(), asnDetail.getOrderNumber());


        //生成入库记录
        Task task = new Task(item, itemKey, asnDetail.getOrderNumber(), BizStatus.ASN, asnDetail, null, null, null, stock, stock, null, endPoint, null, null, null, endPoint.getCode(), null, BizStatus.OPEN, asnDetail.getOrderQty(), null, null, item.getDept(), null);
        taskService.create(task);
        return task;
    }

}
