package com.zd.laboratory.controller;

import com.zd.common.core.constant.HttpStatus;
import com.zd.common.core.domain.R;
import com.zd.common.core.domain.per.PerFun;
import com.zd.common.core.domain.per.PerPrefix;
import com.zd.common.core.enums.HardwareOperate;
import com.zd.common.core.enums.HardwareTypeEnum;
import com.zd.common.core.exception.ServiceException;
import com.zd.common.core.utils.SecurityUtils;
import com.zd.common.core.utils.bean.TransferUtils;
import com.zd.common.core.utils.poi.ExcelUtil;
import com.zd.common.core.web.controller.BaseController;
import com.zd.common.core.web.domain.AjaxResult;
import com.zd.common.core.web.domain.ResultData;
import com.zd.common.core.web.page.TableDataInfo;
import com.zd.common.log.annotation.Log;
import com.zd.common.log.enums.BusinessType;
import com.zd.common.redis.service.RedisService;
import com.zd.common.security.annotation.PreAuthorize;
import com.zd.common.security.service.TokenService;
import com.zd.laboratory.domain.LabHardware;
import com.zd.laboratory.domain.vo.HxpSmartTerminalByExcel;
import com.zd.laboratory.domain.vo.LabHardwareVO;
import com.zd.laboratory.domain.vo.LabSensorVO;
import com.zd.laboratory.service.ILabHardwareService;
import com.zd.laboratory.service.ILabSensorService;
import com.zd.laboratory.service.ILabSubjectService;
import com.zd.laboratory.service.impl.LabSubjectManagerService;
import com.zd.laboratory.socket.command.Symbol;
import com.zd.system.api.laboratory.domain.FunctionStatus;
import com.zd.system.api.laboratory.domain.RemoteLabHardware;
import com.zd.system.api.laboratory.domain.vo.HardwareCVO;
import com.zd.system.api.netty.RemoteNettyService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 硬件Controller
 *
 * @author zd
 * @date 2021-08-30
 */
@RestController
@RequestMapping("/hardware")
public class LabHardwareController extends BaseController {
    @Autowired
    private ILabHardwareService labHardwareService;

    @Autowired
    private ILabSensorService labSensorService;

    @Autowired
    private ILabSubjectService labSubjectService;

    @Autowired
    LabSubjectManagerService subjectManagerService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    RedisService redisService;
    @Resource
    private RemoteNettyService nettyService;

    /**
     * 查询硬件统计
     * @return
     */
    @PreAuthorize(hasAnyPermi = {PerPrefix.LABORATORY_HARDWARE + PerFun.LIST,PerPrefix.LABORATORY_HARDWARE5 + PerFun.LIST,
            PerPrefix.LABORATORY_HARDWARE6 + PerFun.LIST,PerPrefix.LABORATORY_HARDWARE7 + PerFun.LIST,PerPrefix.LABORATORY_HARDWARE8 + PerFun.LIST
            ,PerPrefix.LABORATORY_HARDWARE9 + PerFun.LIST})
    @GetMapping("/statistics")
    public AjaxResult statistics() {
        Map<String, Object> map = labHardwareService.selectStatistics(new LabHardware());
        return AjaxResult.success(map);
    }

    /**
     * 查询硬件列表
     */
    @PreAuthorize(hasAnyPermi = {PerPrefix.LABORATORY_HARDWARE + PerFun.LIST,PerPrefix.LABORATORY_HARDWARE5 + PerFun.LIST,
            PerPrefix.LABORATORY_HARDWARE6 + PerFun.LIST,PerPrefix.LABORATORY_HARDWARE7 + PerFun.LIST,PerPrefix.LABORATORY_HARDWARE8 + PerFun.LIST
            ,PerPrefix.LABORATORY_HARDWARE9 + PerFun.LIST,PerPrefix.LABORATORY_HARDWARE10 + PerFun.LIST})
    @GetMapping("/list")
    public TableDataInfo<LabHardwareVO> list(LabHardware labHardware) {
        startPage();
        List<LabHardwareVO> list = labHardwareService.selectLabHardwareList(labHardware);
        return getDataTable(list);
    }

    /**
     * 查询硬件的下拉框接口
     */
    @PostMapping("/queryOption")
    public AjaxResult queryOption(@RequestBody LabHardware labHardware) {
        List<LabHardwareVO> list = labHardwareService.selectLabHardwareList(labHardware);
        return AjaxResult.success(list);
    }


    /**
     * 查询硬件类型下拉框
     */
    @PostMapping("/queryHardwareType")
    public AjaxResult queryHardwareType() {
        HardwareTypeEnum[] list = HardwareTypeEnum.values();
        return AjaxResult.success(list);
    }


    /**
     * 导出硬件列表
     */
    @PreAuthorize(hasPermi = PerPrefix.LABORATORY_HARDWARE + PerFun.EXPORT)
    @Log(title = "硬件", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, LabHardware labHardware) throws IOException {
        List<LabHardwareVO> list = labHardwareService.selectLabHardwareList(labHardware);
        ExcelUtil<LabHardwareVO> util = new ExcelUtil<>(LabHardwareVO.class);
        util.exportExcel(response, list, "硬件数据");
    }

    /**
     * 获取硬件详细信息
     */
    @PreAuthorize(hasPermi = PerPrefix.LABORATORY_HARDWARE + PerFun.QUERY)
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return AjaxResult.success(labHardwareService.selectLabHardwareById(id));
    }

    /**
     * 查询硬件详细信息，包涵实验室下的所有硬件
     */
    @GetMapping("/getHardwareDetail")
    public AjaxResult getHardwareDetail(LabHardware labHardware) {
        LabHardwareVO list = labHardwareService.getHardwareDetail(labHardware);
        return AjaxResult.success(list);
    }

    /**
     * 新增硬件
     */
    @PreAuthorize(hasAnyPermi = {PerPrefix.LABORATORY_HARDWARE + PerFun.ADD,PerPrefix.LABORATORY_HARDWARE5 + PerFun.ADD,
            PerPrefix.LABORATORY_HARDWARE6 + PerFun.ADD,PerPrefix.LABORATORY_HARDWARE7 + PerFun.ADD,PerPrefix.LABORATORY_HARDWARE8 + PerFun.ADD
            ,PerPrefix.LABORATORY_HARDWARE9 + PerFun.ADD})
    @Log(title = "硬件", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody LabHardware labHardware) {
        return toAjax(labHardwareService.insertLabHardware(labHardware));
    }

    /**
     * 修改硬件
     */
    @PreAuthorize(hasAnyPermi = {PerPrefix.LABORATORY_HARDWARE + PerFun.EDIT,PerPrefix.LABORATORY_HARDWARE5 + PerFun.EDIT,
            PerPrefix.LABORATORY_HARDWARE6 + PerFun.EDIT,PerPrefix.LABORATORY_HARDWARE7 + PerFun.EDIT,PerPrefix.LABORATORY_HARDWARE8 + PerFun.EDIT
            ,PerPrefix.LABORATORY_HARDWARE9 + PerFun.EDIT,PerPrefix.LABORATORY_HARDWARE10 + PerFun.EDIT})
    @Log(title = "硬件", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody LabHardware labHardware) {
        return toAjax(labHardwareService.updateLabHardware(labHardware));
    }

    /**
     * 设置柜锁时间
     */
    @PreAuthorize(hasAnyPermi = {PerPrefix.LABORATORY_HARDWARE + PerFun.EDIT,PerPrefix.LABORATORY_HARDWARE5 + PerFun.EDIT,
            PerPrefix.LABORATORY_HARDWARE6 + PerFun.EDIT,PerPrefix.LABORATORY_HARDWARE7 + PerFun.EDIT,PerPrefix.LABORATORY_HARDWARE8 + PerFun.EDIT
            ,PerPrefix.LABORATORY_HARDWARE9 + PerFun.EDIT})
    @Log(title = "设置柜锁时间", businessType = BusinessType.UPDATE)
    @PutMapping("/setLock")
    public AjaxResult setLock(@RequestBody LabHardwareVO labHardwareVO) {
        return toAjax(labHardwareService.setLock(labHardwareVO));
    }


    /**
     * 删除硬件
     */
    @PreAuthorize(hasAnyPermi = {PerPrefix.LABORATORY_HARDWARE + PerFun.REMOVE,PerPrefix.LABORATORY_HARDWARE5 + PerFun.REMOVE,
            PerPrefix.LABORATORY_HARDWARE6 + PerFun.REMOVE,PerPrefix.LABORATORY_HARDWARE7 + PerFun.REMOVE,PerPrefix.LABORATORY_HARDWARE8 + PerFun.REMOVE
            ,PerPrefix.LABORATORY_HARDWARE9 + PerFun.REMOVE,PerPrefix.LABORATORY_HARDWARE10 + PerFun.REMOVE})
    @Log(title = "硬件", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(labHardwareService.deleteLabHardwareByIds(ids));
    }

    /**
     * 查询硬件功能列表
     */
    @PostMapping("/getFunList")
    public List<HardwareCVO> getFunList() {
        Map <HardwareTypeEnum, List <FunctionStatus>> list = labHardwareService.getFunList();

        return Optional.ofNullable(list)
                .filter(a -> a.size() > 0)
                .orElseGet(Collections::emptyMap)
                .entrySet()
                .stream()
                .map(a -> {

                    HardwareCVO hardwareCVO = new HardwareCVO();
                    hardwareCVO.setHardwareTypeEnum(a.getKey());
                    hardwareCVO.setFunctionStatusList(a.getValue());
                    return hardwareCVO;
                }).collect(Collectors.toList());

    }

    /***
     * 根据实验室id查询该实验室下的硬件信息
     * @return
     */
    @ApiOperation(value = "据实验室id查询该实验室下的硬件信息")
    @GetMapping("/listBySubjectId")
    public AjaxResult listBySubjectId(Long subjectId)
    {
        Map<String,Object> map = new HashMap<>();
        //1传感器 2一体机 3控制设备 4摄像头
        LabHardwareVO ytjVo=new LabHardwareVO();
        ytjVo.setSubjectId(subjectId);

        //一体机查询
        ytjVo.setType(HardwareTypeEnum.ONE_MACHINE);
        List<LabHardwareVO> listYtj=labHardwareService.selectLabHardwareList(ytjVo);

        //摄像头
        ytjVo.setType(HardwareTypeEnum.VIDEO_MONITOR);
        List<LabHardwareVO> listSpjk=labHardwareService.selectLabHardwareList(ytjVo);

        //传感器
        LabSensorVO labSensorVO = new LabSensorVO();
        labSensorVO.setSubjectId(subjectId);
        List<LabSensorVO> listCgq= labSensorService.selectLabSensorList(labSensorVO);

        /*//控制设备-电源开关
        ytjVo.setType(HardwareTypeEnum.SWITCH);
        List<LabHardwareVO> listDykg=labHardwareService.selectLabHardwareList(ytjVo);

        //控制设备-智能通风
        ytjVo.setType(HardwareTypeEnum.AI_VENTILATION);
        List<LabHardwareVO> listZntf=labHardwareService.selectLabHardwareList(ytjVo);*/

        List<Long> ids = new ArrayList<>();
        ids.add(1L);//电源开关
        ids.add(2L);//智能通风
        ytjVo.setIds(ids);
        List<LabHardware> listkzsb=labHardwareService.selectNewLabHardwareByTypes(ytjVo);

        //实验室详情
        //LabSubject labSubject =labSubjectService.selectLabSubjectById(subjectId);

        map.put("listYtj",listYtj);//一体机
        //map.put("listDykg",listDykg);//控制设备-电源开关
        //map.put("listZntf",listZntf);//控制设备-智能通风
        map.put("listSpjk",listSpjk); //摄像头
        map.put("listCgq",listCgq); //传感器
        map.put("listkzsb",listkzsb); //控制设备
        //map.put("labSubject",labSubject); //实验室详情
        return AjaxResult.success(map);

    }



    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response) throws IOException {
        String tips = "导入注意事项：（未按如下要求填写，会导致数据不能正常导入）\n" +
                "1、请不要修改此表格的格式，包括插入删除行和列、合并拆分单元格等。请在表格里面逐行录入数据。一次最多导入5000条数据信息。\n" +
                "2、需要填写的单元格字段规则校验，请按照提示输入。\n" +
                "3、请不要随意复制单元格，这样会破坏字段规则校验。\n" +
                "4、带有星号（*）的红色字段为必填项。\n" +
                "5、请注意：设备编号是唯一的，不能重复，不可多条；编号要求最大20个字符，包含大小写字母、数字。\n" +
                "6、请注意：实验室，需填写系统中已录入的对应数据名称，否则无法正常导入。\n";
        ExcelUtil<HxpSmartTerminalByExcel> util = new ExcelUtil<>(HxpSmartTerminalByExcel.class);
        util.exportExcel(response, null, "化学品智能终端", tips, "化学品智能终端-批量导入模板");
    }

    @Log(title = "化学品导入", businessType = BusinessType.IMPORT)
    @PreAuthorize(hasAnyPermi = {PerPrefix.LABORATORY_HARDWARE + PerFun.IMPORT,PerPrefix.LABORATORY_HARDWARE5 + PerFun.IMPORT,
            PerPrefix.LABORATORY_HARDWARE6 + PerFun.IMPORT,PerPrefix.LABORATORY_HARDWARE7 + PerFun.IMPORT,PerPrefix.LABORATORY_HARDWARE8 + PerFun.IMPORT
            ,PerPrefix.LABORATORY_HARDWARE9 + PerFun.IMPORT})
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file, HxpSmartTerminalByExcel hxpChemicalByExcel) throws Exception {
        ExcelUtil<HxpSmartTerminalByExcel> util = new ExcelUtil<>(HxpSmartTerminalByExcel.class);
        List<HxpSmartTerminalByExcel> smartTerminalList = util.importExcel(file.getInputStream(), true);
        String operName = SecurityUtils.getUsername();
        try{
            List<HxpSmartTerminalByExcel> hxpSmartTerminalByExcels = labHardwareService.importSmartTerminal(smartTerminalList, operName, hxpChemicalByExcel);
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("totalNum", smartTerminalList.size());
            resultMap.put("successNum", smartTerminalList.size() - hxpSmartTerminalByExcels.size());
            resultMap.put("failureNum", hxpSmartTerminalByExcels.size());
            resultMap.put("downFile", !hxpSmartTerminalByExcels.isEmpty());
            if (!hxpSmartTerminalByExcels.isEmpty()) {
                redisService.setCacheObject("exportBySmartTerminal" + SecurityUtils.getUserId(), hxpSmartTerminalByExcels, 1L, TimeUnit.HOURS);
            }
            return AjaxResult.success(resultMap);
        }catch (Exception e){
            throw new ServiceException("导入模板有误，请重新导入!");
        }

    }

    @Log(title = "化学品导入出错误数据", businessType = BusinessType.IMPORT)
    @PostMapping("/importErrorData")
    public void importErrorData(HttpServletResponse response) throws Exception {
        String tips = "导入注意事项：（未按如下要求填写，会导致数据不能正常导入）\n" +
                "1、请不要修改此表格的格式，包括插入删除行和列、合并拆分单元格等。请在表格里面逐行录入数据。一次最多导入5000条数据信息。\n" +
                "2、需要填写的单元格字段规则校验，请按照提示输入。\n" +
                "3、请不要随意复制单元格，这样会破坏字段规则校验。\n" +
                "4、带有星号（*）的红色字段为必填项。\n" +
                "5、请注意：设备编号是唯一的，不能重复，不可多条；编号要求最大20个字符，包含大小写字母、数字。\n" +
                "6、请注意：实验室，需填写系统中已录入的对应数据名称，否则无法正常导入。\n";
        ExcelUtil<HxpSmartTerminalByExcel> util = new ExcelUtil<>(HxpSmartTerminalByExcel.class);
        List<HxpSmartTerminalByExcel> smartTerminalByExcels = redisService.getCacheObject("exportBySmartTerminal" + SecurityUtils.getUserId());
        if (!smartTerminalByExcels.isEmpty()) {
            util.exportExcel(response, smartTerminalByExcels, "未导入的智能终端数据数据", tips, "智能终端批量导入模板");
        }
    }


    @GetMapping("/getCabinetLockList")
    @PreAuthorize(hasPermi = PerPrefix.LABORATORY_HARDWARE9 + PerFun.JOINCABINET)
    public TableDataInfo<LabHardwareVO> getCabinetLockList(LabHardware labHardware) {
        labHardware.setType(HardwareTypeEnum.AI_CABINETLOCK);
        List<LabHardwareVO> list = labHardwareService.getCabinetLockList(labHardware);
        return getDataTable(list);
    }


    /**
     * 关联的机柜id
     */
    @Log(title = "关联的机柜id", businessType = BusinessType.UPDATE)
    @PutMapping("/setLockJoinCabinet")
    public AjaxResult setLockJoinCabinet(@RequestBody List<LabHardware> hardwares) {
        return toAjax(labHardwareService.setLockJoinCabinet(hardwares));
    }

    /**
     * 查询机柜绑定柜锁列表
     */
    @RequestMapping("/getHardwareByLockList")
    @ApiOperation(value = "查询化学品机柜管理信息列表")
    public ResultData <List<LinkedHashMap<String,String>>> getCabinetList(@RequestBody LabHardware labHardware) {
        labHardware.setType(HardwareTypeEnum.AI_CABINETLOCK);
        List<LabHardwareVO> list = labHardwareService.selectLabHardwareByCabinetList(labHardware);
        List<LinkedHashMap<String,String>> cabinetList = Optional.ofNullable(list).orElseGet(Collections::emptyList).stream()
                .map(a->{
                    LinkedHashMap<String,String> toMap = new LinkedHashMap();
                    toMap.put("id",a.getId()+"");
                    toMap.put("joinCabinetId",a.getJoinCabinetId());
                    toMap.put("lockName",a.getName());
                    return toMap;
                })
                .collect(Collectors.toList());
        return ResultData.success(cabinetList);
    }

    /**
     * 启/停用
     */
    @ApiOperation(value = "启/停用")
    @Log(title = "启/停用", businessType = BusinessType.UPDATE)
    @PutMapping("start/{id}")
    public ResultData<Boolean> startOrStop(@PathVariable("id") Long id) {
        LabHardwareVO labHardwareVO = labHardwareService.selectLabHardwareById(id);
        if (labHardwareVO==null){
            return ResultData.fail("查询出错");
        }
        if (labHardwareVO.getIpAddress()==null){
            return ResultData.fail("设备尚未配置IP");
        }
        RemoteLabHardware remoteLabHardware=new RemoteLabHardware();
        BeanUtils.copyProperties(labHardwareVO,remoteLabHardware);
        remoteLabHardware.setType(labHardwareVO.getType().getHardwareTypeCode());
        HardwareOperate operate = labHardwareVO.getOperate();
        if (operate==null || operate.getCode()==4){
            subjectManagerService.control(id, Symbol.command.open);
            R<Boolean> result = nettyService.startMonitorChannels(remoteLabHardware);
            if (result.getCode()== HttpStatus.SUCCESS){
                operate=HardwareOperate.OPEN;
            }else {
                return ResultData.fail(result.getMsg());
            }
        }else {
            subjectManagerService.control(id, Symbol.command.close);
            R<Boolean> result = nettyService.disconnect(remoteLabHardware);
            if (result.getCode()== HttpStatus.SUCCESS){
                operate=HardwareOperate.CLOSE;
            }else {
                return ResultData.fail(result.getMsg());
            }
        }
        LabHardware hardware=new LabHardware();
        hardware.setId(id);
        hardware.setOperate(operate);
        labHardwareService.startOrStop(hardware);
        return ResultData.success(true,operate.getName()+"成功");
    }

    /**
     * netty服务查询识别器列表
     */
    @GetMapping("/list/start")
    @ApiOperation(value = "netty服务查询识别器列表")
    public R<List<RemoteLabHardware>> listStart(){
        LabHardware hardware = new LabHardware();
        hardware.setOperate(HardwareOperate.OPEN);
        hardware.setType(HardwareTypeEnum.RFID_RECOGNIZER);
        List<LabHardwareVO> labHardwareVOS = labHardwareService.selectLabHardwareList(hardware);
        return R.ok(TransferUtils.transferList(labHardwareVOS,RemoteLabHardware.class));
    }

    /**
     * 查询硬件的下拉框接口
     */
    @PostMapping("/remote/list")
    public R<List<RemoteLabHardware>> remoteList(@RequestBody RemoteLabHardware remoteLabHardware) {
        LabHardware hardware = new LabHardware();
        BeanUtils.copyProperties(remoteLabHardware,hardware);
        hardware.setType(HardwareTypeEnum.getByCode(remoteLabHardware.getType()));
        List<LabHardwareVO> list = labHardwareService.selectLabHardwareList(hardware);
        return R.ok(TransferUtils.transferList(list,RemoteLabHardware.class));
    }

    /**
     * 修改识别器状态
     */
    @ApiOperation(value = "修改识别器状态")
    @Log(title = "修改识别器状态", businessType = BusinessType.UPDATE)
    @PutMapping("update")
    public R<Integer> update(@RequestParam("operate") HardwareOperate operate, @RequestParam("ipAddress") String ipAddress) {
        LabHardware hardware=new LabHardware();
        hardware.setIpAddress(ipAddress);
        List<LabHardwareVO> hardwareVOS = labHardwareService.selectLabHardwareList(hardware);
        if (hardwareVOS.size()>1){
            throw new ServiceException("设备IP:"+ipAddress+"\tIP重复");
        }
        LabHardwareVO hardwareVO = hardwareVOS.get(0);
        BeanUtils.copyProperties(hardwareVO,hardware);
        hardware.setOperate(operate);
        return R.ok(labHardwareService.updateLabHardware(hardware));
    }



    /**
     * 查询硬件列表
     */
    @GetMapping("/getEnablelist")
    public TableDataInfo<LabHardwareVO> getEnablelist(LabHardware labHardware) {
        labHardware.setDeviceStatus(1);
        List<LabHardwareVO> list = labHardwareService.selectLabHardwareList(labHardware);
        return getDataTable(list);
    }
}
