package com.tykj.dev.rfid.controller;


import com.tykj.dev.config.swagger.AutoDocument;
import com.tykj.dev.device.library.service.DeviceLibraryService;
import com.tykj.dev.device.library.service.DeviceLogService;
import com.tykj.dev.device.library.subject.Dto.DeviceLogDto;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.device.library.subject.vo.DeviceLibrarySelectVo;
import com.tykj.dev.device.library.subject.vo.FileVo;
import com.tykj.dev.device.task.service.TaskLogService;
import com.tykj.dev.device.task.service.TaskService;
import com.tykj.dev.device.task.subject.bto.TaskBto;
import com.tykj.dev.device.task.subject.bto.TaskLogBto;
import com.tykj.dev.device.task.subject.common.BusinessEnum;
import com.tykj.dev.device.task.subject.common.StatusEnum;
import com.tykj.dev.device.task.subject.domin.Task;
import com.tykj.dev.device.user.subject.entity.User;
import com.tykj.dev.device.user.subject.service.UserPublicService;
import com.tykj.dev.device.user.util.AuthenticationUtils;
import com.tykj.dev.misc.utils.ListUtil;
import com.tykj.dev.misc.utils.ResultUtil;
import com.tykj.dev.rfid.entity.domin.LibraryWarningLog;
import com.tykj.dev.rfid.entity.domin.RfidChangeBill;
import com.tykj.dev.rfid.entity.domin.RfidChangeLog;
import com.tykj.dev.rfid.entity.enums.RfidChangeStatus;
import com.tykj.dev.rfid.entity.vo.*;
import com.tykj.dev.rfid.service.LibraryWarningLogService;
import com.tykj.dev.rfid.service.RfidChangeBillService;
import com.tykj.dev.rfid.service.RfidChangeLogService;
import com.tykj.dev.rfid.service.RfidService;
import com.tykj.dev.rfid.timeTask.InventoryScheduled;
import com.tykj.dev.socket.MyWebSocket;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

/**
 * @author huangxiahao
 */
@RestController
@Api(tags = "RFID模块",value = "RFID模块")
@AutoDocument
@RequestMapping("/rfid")
public class RfidController {

    private final RfidService rfidService;

    private final LibraryWarningLogService libraryWarningLogService;

    @Resource
    DeviceLibraryService deviceLibraryService;

    @Resource
    UserPublicService userPublicService;

    @Resource
    TaskService taskService;

    @Resource
    TaskLogService taskLogService;

    @Resource
    DeviceLogService deviceLogService;

    @Resource
    MyWebSocket myWebSocket;

    @Autowired
    private AuthenticationUtils AuthenticationUtils;

    final RfidChangeLogService rfidChangeLogService;

    final RfidChangeBillService rfidChangeBillService;

    InventoryScheduled inventoryScheduled;

    public RfidController(RfidChangeLogService rfidChangeLogService, RfidService rfidService, LibraryWarningLogService libraryWarningLogService, RfidChangeBillService rfidChangeBillService, InventoryScheduled inventoryScheduled) {
        this.rfidChangeLogService = rfidChangeLogService;
        this.rfidService = rfidService;
        this.libraryWarningLogService = libraryWarningLogService;
        this.rfidChangeBillService = rfidChangeBillService;
        this.inventoryScheduled = inventoryScheduled;
    }

    @ApiOperation(value = "生成RFID表面号", notes = "可以通过这个接口生成RFID表面号")
    @PostMapping(value = "/createRFID")
    public ResponseEntity createRfid(@RequestBody List<RfidCreateVo> list) {
        return ResultUtil.success(rfidService.getRfidNumber(list));
    }

    @ApiOperation(value = "打印标签", notes = "可以通过这个接口打印RFID")
    @PostMapping(value = "/print")
    public ResponseEntity printRfid(@RequestBody List<String> rfid) {
        //调用打印服务 批量打印
        for (String rfidContent : rfid) {
            rfidService.printString(rfidContent);
        }
        return ResultUtil.success("打印成功");
    }


    @ApiOperation(value = "标签制作表单提交", notes = "标签制作表单提交")
    @PostMapping(value = "/form")
    @Transactional(rollbackOn = Exception.class)
    public ResponseEntity form(@Validated @RequestBody RfidFormVo formVo) {
        //获取当前登录用户
        User currentUserInfo = Objects.requireNonNull(AuthenticationUtils.getAuthentication()).getCurrentUserInfo();
        //生成账单
        RfidChangeBill rfidChangeBill = RfidChangeBill.formVoToBill(formVo, currentUserInfo);
        RfidChangeBill rfidChangeBillSaved = rfidChangeBillService.addEntity(rfidChangeBill);
        //生成日志所需的文件列表
        ArrayList<FileVo> billList = ListUtil.createList(
                new FileVo("标签替换单据", rfidChangeBill.getFileName(), rfidChangeBill.getFileUrl())
        );
        //遍历每一件需要修改标签的装备号
        formVo.getContent().forEach(d->{
            //生成详情信息
            rfidChangeLogService.addEntity(initRfidChangeLog(currentUserInfo, rfidChangeBillSaved, d));
            //生成装备变更日志
            deviceLogService.addLog(new DeviceLogDto(d.getDeviceId(),"发起标签替换",billList));
            deviceLogService.addLog(new DeviceLogDto(d.getDeviceId(),"标签替换待审核",billList));
        });
        //生成Task
        Task task = taskService.start(initTaskBto(currentUserInfo, rfidChangeBillSaved));
        //生成任务日志
        taskLogService.addLog(new TaskLogBto(task.getId(),"发起标签替换",billList));
        taskLogService.addLog(new TaskLogBto(task.getId(),"标签替换待审核",billList));
        myWebSocket.sendMessage1();;
        return ResultUtil.success("标签修改申请成功");
    }

    @ApiOperation(value = "查询标签修改详情", notes = "可以通过这个接口查询销毁单")
    @GetMapping(value = "/detail")
    public ResponseEntity selectRfidChangeDetail(@Validated @NotNull Integer billId) {
        RfidChangeBillResultVo rfidChangeBillResultVo = new RfidChangeBillResultVo();
        RfidChangeBill rfidChangeBill = rfidChangeBillService.getOne(billId);
        //获取销毁详情里的装备
        RfidChangeLogSelectVo rfidChangeLogSelectVo = new RfidChangeLogSelectVo();
        rfidChangeLogSelectVo.setBillId(billId);
        List<RfidChangeLog> rfidChangeLogEntities = rfidChangeLogService.getList(rfidChangeLogSelectVo);
        //为标签修改VO里的详情列表添加元素
        rfidChangeLogEntities.forEach(d -> {
            DeviceLibrary device = deviceLibraryService.getOne(d.getDeviceId());
            RfidChangeLogResultVo rfidChangeLogResultVo = new RfidChangeLogResultVo();
            BeanUtils.copyProperties(device,rfidChangeLogResultVo);
            BeanUtils.copyProperties(d,rfidChangeLogResultVo);
            rfidChangeLogResultVo.setUserAName(userPublicService.getOne(d.getUserAId()).getName());
            rfidChangeLogResultVo.setUserBName(userPublicService.getOne(d.getUserBId()).getName());
            rfidChangeBillResultVo.getRfidChangeLogResultVos().add(rfidChangeLogResultVo);
        });
        BeanUtils.copyProperties(rfidChangeBill,rfidChangeBillResultVo);
        rfidChangeBillResultVo.setUserAName(userPublicService.getOne(rfidChangeBill.getUserAId()).getName());
        rfidChangeBillResultVo.setUserBName(userPublicService.getOne(rfidChangeBill.getUserBId()).getName());
        return ResultUtil.success(rfidChangeBillResultVo);
    }

    @ApiOperation(value = "审核确认", notes = "可以通过这个确认销毁单")
    @PutMapping(value = "/confirmation")
    @Transactional(rollbackOn = Exception.class)
    public ResponseEntity confirmDestory(@RequestBody @Validated RfidChangeConfirmVo rfidChangeConfirmVo) {
        //初始化需要的数据
        TaskBto task = taskService.get(rfidChangeConfirmVo.getTaskId());
        RfidChangeBill rfidChangeBill = rfidChangeBillService.getOne(task.getBillId());
        //生成日志所需的文件列表
        ArrayList<FileVo> billList = ListUtil.createList(
                new FileVo("标签替换单据", rfidChangeBill.getFileName(), rfidChangeBill.getFileUrl())
        );
        //更改账单状态 0为审核成功  否则为审核失败
        rfidChangeBill.setStatus(rfidChangeConfirmVo.getResult() == 0 ? RfidChangeStatus.CONFIRM_SUCCESS.getStatus() : RfidChangeStatus.CONFIRM_FAILED.getStatus());
        //处理详情和生成日志
        handleBillDetail(task,billList,rfidChangeConfirmVo.getResult());
        //生成任务变更日志
        taskLogService.addLog(new TaskLogBto(task.getId(),rfidChangeConfirmVo.getResult()==0?"标签替换审核成功":"标签替换审核失败",billList));
        //更新账单
        rfidChangeBillService.updateEntity(rfidChangeBill);
        myWebSocket.sendMessage1();
        return selectRfidChangeDetail(rfidChangeBill.getId());
    }

    @ApiOperation(value = "标签管理概览", notes = "通过这个借口可以查看标签管理的概览")
    @PostMapping(value = "/summary")
    public ResponseEntity getTagSummary(@RequestBody DeviceLibrarySelectVo deviceLibrarySelectVo) {
        Page<DeviceLibrary> deviceLibraryEntities = deviceLibraryService.getPage(deviceLibrarySelectVo, deviceLibrarySelectVo.getPageable());
        return ResultUtil.success(deviceLibraryEntities);
    }

    @ApiOperation(value = "盘点管理记录概览", notes = "可以通过这个接口查询库房盘点记录")
    @PostMapping(value = "/warehouse/summary")
    public ResponseEntity warehouseSummary(@RequestBody WarehouseLogSelectVo inventoryLogSelectVo) throws ParseException {
        return ResultUtil.success(libraryWarningLogService.getPage(inventoryLogSelectVo.toWarningVo()));
    }

    @ApiOperation(value = "盘点时间设置", notes = "可以通过这个接口查询库房盘点记录")
    @PutMapping(value = "/warehouse/time")
    public ResponseEntity warehouseTime(@NotNull @Min(0) Integer time) {
        String cron = "0 0/" + time + " * * * ? ";
        inventoryScheduled.setCron(cron);
        return ResultUtil.success("修改成功");
    }

    @ApiOperation(value = "出入库记录概览", notes = "可以通过这个接口查询出入库记录")
    @PostMapping(value = "/inout/summary")
    public ResponseEntity inoutSummary(@RequestBody InputOutpuLogSelectVo inputOutpuLogSelectVo) throws ParseException {
        return ResultUtil.success(libraryWarningLogService.getPage(inputOutpuLogSelectVo.toWarningVo()));
    }

    @ApiOperation(value = "告警管理概览", notes = "可以通过这个接口查询当前单位库房告警日志")
    @PostMapping(value = "/alert/summary")
    public ResponseEntity alertSummary(@RequestBody WaringLogSelectVo waringLogSelectVo) throws ParseException {
        //todo 这里改了返回样式记得通知前端
        HashMap<String, Object> map = new HashMap<>();
        Page<LibraryWarningLog> page = libraryWarningLogService.getPage(waringLogSelectVo.toWarningVo());
        WarningCountVo warningCountVo = libraryWarningLogService.getCount(waringLogSelectVo.toWarningVo());
        map.put("pageContent", page);
        map.put("count", warningCountVo);
        return ResultUtil.success(map);
    }

    @ApiOperation(value = "首页告警日志查询", notes = "可以通过这个接口查询当前单位库房告警日志")
    @PostMapping(value = "/indexWarningLog")
    public ResponseEntity indexWarningLog(@RequestBody IndexLogSelectVo indexLogSelectVo) throws ParseException {
        return ResultUtil.success(libraryWarningLogService.getPage(indexLogSelectVo.toWarningVo()));
    }

    @ApiOperation(value = "盘点日志详情", notes = "可以通过这个接口查询盘点日志详情")
    @PostMapping(value = "/warehouse/warningDetail")
    public ResponseEntity warehouseWarningDetail(@RequestBody WarningDetailSelectVo warningDetailSelectVo) {
        WarehouseWarningDetailVo warehouseWarningDetailVo = new WarehouseWarningDetailVo();
        List<WarningDetailListVo> warningDetails = libraryWarningLogService.getWarningDetail(warningDetailSelectVo.getWarningId(), null);
        warehouseWarningDetailVo.setDetailListVos(warningDetails);
        LibraryWarningLog libraryWarningLog = libraryWarningLogService.getOne(warningDetailSelectVo.getWarningId());
        BeanUtils.copyProperties(libraryWarningLog, warehouseWarningDetailVo);
        return ResultUtil.success(warehouseWarningDetailVo);
    }

    @ApiOperation(value = "出入库告警日志详情", notes = "可以通过这个接口查询出入库告警日志详情")
    @PostMapping(value = "/inout/warningDetail")
    public ResponseEntity inoutWarningDetail(@RequestBody WarningDetailSelectVo warningDetailSelectVo) {
        InoutWarningDetailVo inoutWarningDetailVo = new InoutWarningDetailVo();
        List<WarningDetailListVo> warningDetails = libraryWarningLogService.getWarningDetail(warningDetailSelectVo.getWarningId(), null);
        inoutWarningDetailVo.setDetailListVos(warningDetails);
        LibraryWarningLog libraryWarningLog = libraryWarningLogService.getOne(warningDetailSelectVo.getWarningId());
        BeanUtils.copyProperties(libraryWarningLog, inoutWarningDetailVo);
        return ResultUtil.success(inoutWarningDetailVo);
    }

    @ApiOperation(value = "库房告警日志详情", notes = "可以通过这个接口查询告警日志详情")
    @PostMapping(value = "/warningDetail")
    public ResponseEntity warningDetail(@RequestBody WarningDetailSelectVo warningDetailSelectVo) {
        WarningDetailVo warningDetailVo = new WarningDetailVo();
        List<WarningDetailListVo> warningDetails = libraryWarningLogService.getWarningDetail(warningDetailSelectVo.getWarningId(), null);
        warningDetailVo.setDetailListVos(warningDetails);
        LibraryWarningLog libraryWarningLog = libraryWarningLogService.getOne(warningDetailSelectVo.getWarningId());
        BeanUtils.copyProperties(libraryWarningLog, warningDetailVo);
        return ResultUtil.success(warningDetailVo);
    }

    @ApiOperation(value = "告警处理", notes = "可以通过这个接口处理告警")
    @PutMapping(value = "/warningHandle")
    public ResponseEntity warehouseWarningHandle(@RequestBody List<WarningHandleVo> warningHandleVos) {
        Integer logId = 0;
        for (WarningHandleVo warningHandleVo :
                warningHandleVos) {
            logId = libraryWarningLogService.updateDetailHandleResult(warningHandleVo);
        }
        List<WarningDetailListVo> warningDetail = libraryWarningLogService.getWarningDetail(logId, true);
        if (warningDetail.size() == 0) {
            LibraryWarningLog libraryWarningLog = libraryWarningLogService.getOne(logId);
            libraryWarningLog.setWarningHandle(1);
            libraryWarningLogService.update(libraryWarningLog);
        }
        return ResultUtil.success("修改成功");
    }

    @ApiOperation(value = "标签管理详情", notes = "可以通过这个接口查询标签管理详情")
    @GetMapping(value = "/tag/detail")
    public ResponseEntity warningHandle(Integer tagId) {
        //生成查询类
        RfidChangeLogSelectVo rfidChangeLogSelectVo = new RfidChangeLogSelectVo();
        rfidChangeLogSelectVo.setDeviceId(tagId);
        rfidChangeLogSelectVo.setValidTag(1);
        //获取装备信息
        DeviceLibrary device = deviceLibraryService.getOne(tagId);
        //获取标签日志信息
        List<RfidChangeLog> rfidChangeLogEntities = rfidChangeLogService.getList(rfidChangeLogSelectVo);
        List<RfidChangeLogVo> vos = new ArrayList<>();
        rfidChangeLogEntities.forEach(l -> {
            RfidChangeLogVo rfidChangeLogVo = new RfidChangeLogVo();
            BeanUtils.copyProperties(l,rfidChangeLogVo);
            rfidChangeLogVo.setUserAName(userPublicService.getOne(rfidChangeLogVo.getUserAId()).getName());
            rfidChangeLogVo.setUserBName(userPublicService.getOne(rfidChangeLogVo.getUserBId()).getName());
            vos.add(rfidChangeLogVo);
        });
        //组装
        TagDetailVo tagDetailVo = new TagDetailVo(device,vos);
        return ResultUtil.success(tagDetailVo);
    }

    private RfidChangeLog initRfidChangeLog(User currentUserInfo, RfidChangeBill rfidChangeBillSaved, RfidChangeInfoVo d) {
        RfidChangeLog rfidChangeLog = new RfidChangeLog(
                d.getDeviceId(),
                currentUserInfo.getUnits().getName(),
                currentUserInfo.getUserId(),
                rfidChangeBillSaved.getUserBId(),
                d.getOldRfidCardId(),
                d.getNewRfidCardId(),
                rfidChangeBillSaved.getId(),
                0
        );
        return rfidChangeLog;
    }

    private TaskBto initTaskBto(User currentUserInfo, RfidChangeBill rfidChangeBillSaved) {
        TaskBto task = new TaskBto(
                StatusEnum.RFID_BUSINESS_NEED_CONFIRM.id,
                "标签修改业务",
                0,
                ".",
                rfidChangeBillSaved.getId(),
                BusinessEnum.TAG.id,
                currentUserInfo.getUnitsId(),
                1,
                "",
                ListUtil.createList(rfidChangeBillSaved.getUserAId(), rfidChangeBillSaved.getUserBId())
        );
        return task;
    }

    private void handleBillDetail(TaskBto task, ArrayList<FileVo> billList,Integer flag) {
        //构建查询VO
        RfidChangeLogSelectVo rfidChangeLogSelectVo = new RfidChangeLogSelectVo();
        rfidChangeLogSelectVo.setBillId(task.getBillId());
        //查询账单详情
        List<RfidChangeLog> rfidChangeLogEntities = rfidChangeLogService.getList(rfidChangeLogSelectVo);
        rfidChangeLogEntities.forEach(d->{
            if (flag==0){
                //更改对应装备的RFID号
                DeviceLibrary device = deviceLibraryService.getOne(d.getDeviceId());
                device.setRfidCardId(d.getNewCardId());
                deviceLibraryService.update(device);
                //将对应的账单详情记录变为审核成功
                d.setValidTag(1);
                rfidChangeLogService.updateEntity(d);
                //更改对应任务的状态
                taskService.update(taskService.moveToEnd(task));
            }
            else {
                //更改对应任务的状态
                taskService.update(taskService.moveToArchive(task));
            }
            //生成装备日志
            deviceLogService.addLog(new DeviceLogDto(d.getDeviceId(),flag==0?"标签替换成功":"标签替换审核失败",billList));
        });
    }
}
