package com.tykj.dev.rfid.controller;

import com.tykj.dev.config.repository.SystemVariableDao;
import com.tykj.dev.config.service.SystemVariableService;
import com.tykj.dev.config.swagger.AutoDocument;
import com.tykj.dev.device.library.repository.DeviceLibraryDao;
import com.tykj.dev.device.library.service.DeviceLibraryService;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.device.user.subject.service.UserPublicService;
import com.tykj.dev.misc.exception.ApiException;
import com.tykj.dev.misc.utils.JacksonUtil;
import com.tykj.dev.rfid.entity.domin.AccessControlName;
import com.tykj.dev.rfid.entity.domin.InputOutputDevice;
import com.tykj.dev.rfid.entity.domin.LibraryWarningLog;
import com.tykj.dev.rfid.entity.domin.LibraryWarningLogDetail;
import com.tykj.dev.rfid.entity.vo.*;
import com.tykj.dev.rfid.repository.AccessControlNameDao;
import com.tykj.dev.rfid.repository.LibraryWarningLogDetailDao;
import com.tykj.dev.rfid.service.AccessControlNameService;
import com.tykj.dev.rfid.service.InputOutputDeviceService;
import com.tykj.dev.rfid.service.LibraryWarningLogDetailService;
import com.tykj.dev.rfid.service.LibraryWarningLogService;
import io.swagger.annotations.Api;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author dengdiyi
 */
@RestController
@Api(tags = "门禁模块", value = "门禁模块")
@AutoDocument
@RequestMapping("/access")
@Slf4j
public class AccessController {

    @Autowired
    private AccessControlNameDao accessControlNameDao;

    @Autowired
    private AccessControlNameService accessControlNameService;

    @Autowired
    private InputOutputDeviceService inputOutputDeviceService;

    @Resource
    private UserPublicService userPublicService;

    @Resource
    private DeviceLibraryDao deviceLibraryDao;

    @Autowired
    private LibraryWarningLogService libraryWarningLogService;

    @Autowired
    private LibraryWarningLogDetailService libraryWarningLogDetailService;

    @Autowired
    private LibraryWarningLogDetailDao libraryWarningLogDetailDao;

    @Autowired
    private SystemVariableService systemVariableService;

    @PostMapping("/add")
    public ResponseEntity addAccess(@RequestBody AccessControlName accessControlName){
        return ResponseEntity.ok(accessControlNameDao.save(accessControlName));
    }

    @PostMapping("/send")
    public DataResult sendMessage(HttpServletRequest httpServletRequest , HttpServletResponse httpServletResponse) throws IOException {
        //获取门禁传入json
        ServletInputStream inputStream = httpServletRequest.getInputStream();
        BufferedReader bufferedInputStream = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
        StringBuffer sp = new StringBuffer();
        String line ;
        while((line = bufferedInputStream.readLine())!=null){
            sp.append(line);
        }
        String json = sp.toString();
        String cmd = json.substring(10,15);
//        System.out.println(json);
        //数据提交
        if ("20001".equals(cmd)){
            //Json转对象
            AccessData accessData = JacksonUtil.readValue(sp.toString(),AccessData.class);
            if (accessData != null) {
                //获取该门禁设备所属单位
                Integer unitId = accessControlNameService.getByDeviceNo(accessData.getData().getDeviceNo()).getUnitId();
                //可以出库的装备
                List<InputOutputDevice> outputDevices = inputOutputDeviceService.getByUnitIdAndDirection(unitId,1);
//                List<InputOutputDevice> inputDevices = inputOutputDeviceService.getByUnitIdAndDirection(unitId,0);
                //可以出库的装备的卡号
                List<String> canOutputCardIds = outputDevices.stream().map(InputOutputDevice::getRfidCardId).collect(Collectors.toList());
//                List<String> canInputCardIds = outputDevices.stream().map(InputOutputDevice::getRfidCardId).collect(Collectors.toList());
                //实际出库的装备卡号
                List<String> outPutCardIds = accessData.getData().getEpcs().stream()
                        .filter(record -> record.getDirection()==1).map(Record::getEpc)
                        .collect(Collectors.toList());
                //实际入库的装备卡号
                List<String> inPutCardIds = accessData.getData().getEpcs().stream()
                        .filter(record -> record.getDirection()==0).map(Record::getEpc)
                        .collect(Collectors.toList());
//                for (int i = 0;i<outPutCardIds.size();i++){
//                    List<DeviceLibrary> deviceLibraries = deviceLibraryDao.getAllByRfidCardId(outPutCardIds.get(i));
//                    if (deviceLibraries.size()==0){
//
//                    }
//                }
                if (outPutCardIds.size()>0) {
                    //如果实际出库的卡号在可以出库的卡号范围内
                    if (canOutputCardIds.containsAll(outPutCardIds)) {
                        //设置实际出库的装备白名单为已读
                        inputOutputDeviceService.setRead(outputDevices.stream()
                                .filter(inputOutputDevice -> outPutCardIds.contains(inputOutputDevice.getRfidCardId()))
                                .collect(Collectors.toList()));
                        //成功出库不报警
                        log.info("出库"+outPutCardIds.size()+"件装备都在白名单不报警");
                        return DataResult.success();
                    } else {
                        //获取可出库装备和当前出库装备交集
                        canOutputCardIds.retainAll(outPutCardIds);
                        //设置交集的装备白名单为已读
                        inputOutputDeviceService.setRead(outputDevices.stream()
                                .filter(inputOutputDevice -> canOutputCardIds.contains(inputOutputDevice.getRfidCardId()))
                                .collect(Collectors.toList()));
                        //获取所有不在白名单的装备
                        outPutCardIds.removeAll(canOutputCardIds);
                        List<DeviceLibrary> deviceLibraries = new ArrayList<>();
                        outPutCardIds.forEach(s -> deviceLibraries.addAll(deviceLibraryDao.getAllByRfidCardId(s)));
                        //获取最近10s报警的Id
                        List<Integer> ids = getLatestWarningDeviceIds();
                        //排除使用状态中的装备，映射成id
                        List<Integer> idList = deviceLibraries.stream().filter(deviceLibrary -> deviceLibrary.getLifeStatus()!=14).map(DeviceLibrary::getId).collect(Collectors.toList());
                        ids.retainAll(idList);
                        idList.removeAll(ids);
                        if(idList.size()>0) {
                            //对交集外的装备进行告警
                            LibraryWarningLog libraryWarningLog = new LibraryWarningLog();
                            libraryWarningLog.setUnit(userPublicService.findByUnitsToname(unitId));
                            libraryWarningLog.setInventoryResults("异常出库" + idList.size() + "台");
                            libraryWarningLog.setStatus("1");
                            libraryWarningLog.setWarningHandle(0);
                            libraryWarningLog.setWarningType(1);
                            LibraryWarningLog libraryWarningLog1 = libraryWarningLogService.addEntity(libraryWarningLog);
                            //添加详情
                            idList.forEach(integer -> {
                                LibraryWarningLogDetail libraryWarningLogDetail = new LibraryWarningLogDetail();
                                libraryWarningLogDetail.setDeviceId(integer);
                                libraryWarningLogDetail.setInventoryResults("异常出库");
                                libraryWarningLogDetail.setLibraryWarningLogId(libraryWarningLog1.getId());
                                libraryWarningLogDetail.setStatus(1);
                                libraryWarningLogDetail.setWarningHandle(0);
                                libraryWarningLogDetailService.addEntity(libraryWarningLogDetail);
                            });
                            //出库异常报警
                            log.info(idList.size()+"件不在出库白名单的装备出库报警");
                            return DataResult.failed();
                        }
                        //不在系统的rfid不报警
                        else {
                            log.info("出库"+outPutCardIds.size()+"件装备EPC在出库白名单或不存在系统当中不报警");
                            return DataResult.success();
                        }
                    }
                }
                else if(inPutCardIds.size()>0){
                    log.info("入库"+inPutCardIds.size()+"件装备不报警");
                    return DataResult.success();
                }
                else {
                    log.info("未获取到出入库装备EPC不报警");
                    return DataResult.success();
                }
            }
            else {
                throw new ApiException("json转对象异常:对象为Null");
            }
        }
        //时间同步
        else if ("20002".equals(cmd)){
//            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//            TimeConfirm timeConfirm = new TimeConfirm();
//            timeConfirm.setCmd("20002");
//            timeConfirm.setData(new TimeData(0,sdf.format(new Date())));
            return null;
        }
        //心跳包
        else if ("20003".equals(cmd)){
            return null;
        }
        else {
            throw new ApiException("未找到匹配的cmd");
        }
    }

    /**
     * 获取最近10s内出库异常的装备Id
     */
    private List<Integer> getLatestWarningDeviceIds(){
        Long warningInterval = Long.valueOf(systemVariableService.getVaule("warningInterval"));
        return libraryWarningLogDetailDao.findAll().stream().filter(libraryWarningLogDetail -> {
            Boolean isOutPut = "异常出库".equals(libraryWarningLogDetail.getInventoryResults());
            Boolean isLatest = System.currentTimeMillis() - libraryWarningLogDetail.getUpdateTime().getTime()<warningInterval;
            return isOutPut&&isLatest;
        }).map(LibraryWarningLogDetail::getDeviceId).collect(Collectors.toList());
    }
}
