package com.tykj.dev.device.retired.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.packing.repository.PackingLibraryDao;
import com.tykj.dev.device.packing.service.PackingLibraryService;
import com.tykj.dev.device.packing.service.PackingLogService;
import com.tykj.dev.device.packing.subject.domin.PackingLibrary;
import com.tykj.dev.device.packing.subject.domin.PackingLog;
import com.tykj.dev.device.packing.subject.vo.PackingLibrarySelectVo;
import com.tykj.dev.device.retired.entity.domain.DeviceRetiredBill;
import com.tykj.dev.device.retired.entity.enums.RetiredStatus;
import com.tykj.dev.device.retired.entity.vo.*;
import com.tykj.dev.device.retired.service.DeviceRetiredBillService;
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.user.read.service.MessageService;
import com.tykj.dev.device.user.read.subject.bto.MessageBto;
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.device.user.util.UserUtils;
import com.tykj.dev.misc.base.BusinessEnum;
import com.tykj.dev.misc.base.StatusEnum;
import com.tykj.dev.misc.utils.*;
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.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.transaction.Transactional;
import java.sql.Timestamp;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author HuangXiahao
 * @version V1.0
 **/
@RestController
@RequestMapping(value = "/retired")
@AutoDocument
@Api(tags = "退装业务模块", value = "退装业务模块")
public class DeviceRetiredController {

    private final DeviceRetiredBillService deviceRetiredBillService;

    private final TaskService taskService;

    private final PackingLibraryService packingLibraryService;

    private final DeviceLibraryService deviceLibraryService;

    private final DeviceLogService deviceLogService;

    private final TaskLogService taskLogService;
    @Autowired
    MyWebSocket myWebSocket;
    @Autowired
    private AuthenticationUtils AuthenticationUtils;

    @Autowired
    private UserPublicService userPublicService;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private PackingLibraryDao packingLibraryDao;

    @Autowired
    private PackingLogService packingLogService;

    @Autowired
    private MessageService messageService;

    public DeviceRetiredController(DeviceRetiredBillService deviceRetiredBillService, TaskService taskService, PackingLibraryService packingLibraryService, DeviceLibraryService deviceLibraryService, DeviceLogService deviceLogService, TaskLogService taskLogService) {
        this.deviceRetiredBillService = deviceRetiredBillService;
        this.taskService = taskService;
        this.packingLibraryService = packingLibraryService;
        this.deviceLibraryService = deviceLibraryService;
        this.deviceLogService = deviceLogService;
        this.taskLogService = taskLogService;
    }

    @ApiOperation(value = "查询可退装装备", notes = "可以通过这个接口查询销毁单")
    @PostMapping(value = "/devices")
    public ResponseEntity selectRepairBill(@RequestBody CanRetiredDeviceSelectVo canRetiredDeviceSelectVo) {
        //最终返回的List<VO>
        List<DeviceRetiredResultVo> deviceRetiredResultVos = new ArrayList<>();
        //查询类构建
        PackingLibrarySelectVo packingLibrarySelectVo = new PackingLibrarySelectVo();
        BeanUtils.copyProperties(canRetiredDeviceSelectVo, packingLibrarySelectVo);
        List<PackingLibrary> list = GetTreeUtils.splitTree(packingLibraryService.getList(packingLibrarySelectVo),PackingLibrary::getChilds,PackingLibrary::setChildNull);
        //循环获取列装主体的数量，并生成VO
        for(PackingLibrary packingLibrary : list) {
            DeviceRetiredResultVo deviceRetiredResultVo = calcDeviceRetiredResultVo(packingLibrary);
            deviceRetiredResultVos.add(deviceRetiredResultVo);
        }
        List<DeviceRetiredResultVo> deviceRetiredResultVos2 = canRetired(deviceRetiredResultVos);
        Map<Integer, DeviceRetiredResultVo> nodeCollect =
                deviceRetiredResultVos2.stream().collect(Collectors.toMap(DeviceRetiredResultVo::getId, deviceRetiredResultVo -> deviceRetiredResultVo));
        List<DeviceRetiredResultVo> containList = GetTreeUtils.parseTreeFromDown(
                deviceRetiredResultVos2,
                DeviceRetiredResultVo::getId,
                d -> Optional.ofNullable(nodeCollect.get(d.getPartParentId())),
                DeviceRetiredResultVo::addChildNode
        );
        return ResultUtil.success(containList);
    }

    @ApiOperation(value = "提交退装表单", notes = "可以通过这个接口提交销毁表单发起退装流程")
    @PostMapping(value = "/form")
    @Transactional(rollbackOn = Exception.class)
    public ResponseEntity selectRepairBill(@Validated @RequestBody DeviceRetiredFormVo formVo) {
        //生成销毁账单
        User currentUserInfo = Objects.requireNonNull(AuthenticationUtils.getAuthentication()).getCurrentUserInfo();
        DeviceRetiredBill retiredBill = DeviceRetiredBill.formVoToBill(formVo, currentUserInfo);
        retiredBill = deviceRetiredBillService.addEntity(retiredBill);
        //改变列装状态
        formVo.getPackings().forEach(integer -> {
            PackingLibrary packingLibrary = packingLibraryService.getOne(integer);
            packingLibrary.setPackingStatus(3);
            packingLibrary.setExitTime(Timestamp.from(new Date().toInstant()));
            packingLibraryService.update(packingLibrary);
            //添加列装日志
            PackingLog packingLog = new PackingLog();
            packingLog.setRemark("设备退装");
            packingLog.setPackingId(integer);
            packingLogService.add(packingLog);
            setSonsRetired(packingLibrary);
        });
        //生成Task
        TaskBto task = taskService.start(initTaskBto(retiredBill));
        //发送阅知信息
        List<Integer> userIds = userPublicService.findOtherUser(userUtils.getCurrentUserId());
        MessageBto messageBto = new MessageBto(task.getId(),task.getBusinessType(),"业务办结",userIds,0);
        messageBto.setRecord(String.valueOf(task.getBillId()));
        messageService.add(messageBto);
        myWebSocket.sendMessage1();
        return ResultUtil.success("退装申请成功");
    }

    @ApiOperation(value = "查询退装单详情", notes = "可以通过这个接口查询退装单")
    @GetMapping(value = "/detail")
    public ResponseEntity selectDestoryDetail(Integer retiredId) {
        DeviceRetiredDetailResultVo deviceRetiredDetailResultVo = new DeviceRetiredDetailResultVo();
        DeviceRetiredBill deviceRetiredBillEntity = deviceRetiredBillService.getOne(retiredId);
        //获取销毁详情里的装备
        List<Integer> deviceDetails = getRetiredDeviceList(deviceRetiredBillEntity.getRetiredDetail());
        for (Integer deviceId : deviceDetails) {
            deviceRetiredDetailResultVo.getPackingLibrarys().add(packingLibraryService.getOne(deviceId));
        }
        deviceRetiredDetailResultVo.setRetiredStatus(deviceRetiredBillEntity.getRetiredStatus());
        deviceRetiredDetailResultVo.setConfirmUser(userPublicService.getOne(deviceRetiredBillEntity.getUserBId()).getName());
        deviceRetiredDetailResultVo.setStartUser(userPublicService.getOne(deviceRetiredBillEntity.getUserAId()).getName());
        deviceRetiredDetailResultVo.setConfirmUserId(deviceRetiredBillEntity.getUserBId());
        deviceRetiredDetailResultVo.setStartUserId(deviceRetiredBillEntity.getUserAId());
        return ResultUtil.success(deviceRetiredDetailResultVo);
    }

    @ApiOperation(value = "退装出库单审核", notes = "可以通过这个审核退装单")
    @PutMapping(value = "/confirmation")
    @Transactional
    public ResponseEntity confirmDestroy(@RequestBody @Validated DeviceRetiredConfirmVo deviceRetiredConfirmVo) {
        //初始化需要的数据
        TaskBto task = taskService.get(deviceRetiredConfirmVo.getTaskId());
        TaskDisposeUtil.isNotSubmit(task.getBillStatus(),StatusEnum.RETIRED_BUSINESS_NEED_CONFIRM);
        DeviceRetiredBill deviceRetiredBillEntity = deviceRetiredBillService.getOne(task.getBillId());
        //判断审核结果
        if (deviceRetiredConfirmVo.getResult() == 1) {
            //更改账单状态
            deviceRetiredBillEntity.setRetiredStatus(RetiredStatus.CONFIRM_FAILED.getStatus());
            //将任务推进至封存
            taskService.moveToArchive(task);
            taskService.update(task);
        } else {
            //更改账单状态
            deviceRetiredBillEntity.setRetiredStatus(RetiredStatus.CONFIRM_SUCCESS.getStatus());
            //将任务推进至完结
            taskService.moveToEnd(task);
            taskService.update(task);
            //更改对应列装库的状态为退装
            List<Integer> deviceRetiredArrays = getRetiredDeviceList(deviceRetiredBillEntity.getRetiredDetail());
            for (Integer deviceId : deviceRetiredArrays) {
                PackingLibrary packingLibraryServiceOne = packingLibraryService.getOne(deviceId);
                packingLibraryServiceOne.setPackingStatus(3);
                packingLibraryServiceOne.setExitTime(Timestamp.from(new Date().toInstant()));
                packingLibraryService.update(packingLibraryServiceOne);
                setSonsRetired(packingLibraryServiceOne);
                //更改对应的装备为退装
//                changeDeviceToRetired(packingLibraryServiceOne.getId());
            }
        }
        myWebSocket.sendMessage1();
        return selectDestoryDetail(deviceRetiredBillEntity.getId());
    }

    /**
     * 将子列装退装
     */
    private void setSonsRetired(PackingLibrary packingLibrary){
        List<PackingLibrary> sons = packingLibraryDao.findAllByPartParentId(packingLibrary.getId());
        if (sons.size()>0){
            sons.forEach(packingLibrary1 -> {
                packingLibrary1.setPackingStatus(3);
                packingLibrary1.setExitTime(Timestamp.from(new Date().toInstant()));
                packingLibraryService.update(packingLibrary1);
                //添加列装日志
                PackingLog packingLog = new PackingLog();
                packingLog.setRemark("设备退装");
                packingLog.setPackingId(packingLibrary1.getId());
                packingLogService.add(packingLog);
                setSonsRetired(packingLibrary1);
            });
        }
    }


    private List<Integer> getRetiredDeviceList(String destoryDeviceDetail) {
        return StringSplitUtil.split(destoryDeviceDetail);
    }

    private DeviceRetiredResultVo calcDeviceRetiredResultVo(PackingLibrary packingLibraryEntity) {
        DeviceRetiredResultVo deviceRetiredResultVo = new DeviceRetiredResultVo();
        BeanUtils.copyProperties(packingLibraryEntity, deviceRetiredResultVo);
        deviceRetiredResultVo.setCount(deviceRetiredBillService.getCantPackingCount(packingLibraryEntity.getId()));
        deviceRetiredResultVo.setChilds(new ArrayList<>());
//        List<PackingLibrary> PackingChildren = packingLibraryEntity.getChilds();
//        for (PackingLibrary p : PackingChildren) {
//            DeviceRetiredResultVo childDeviceRetiredResultVo = new DeviceRetiredResultVo();
//            BeanUtils.copyProperties(p, childDeviceRetiredResultVo);
//            childDeviceRetiredResultVo.setCount(deviceRetiredBillService.getCantPackingCount(p.getId()));
//            if (p.getChilds()!=null&&!p.getChilds().isEmpty()){
//                for (PackingLibrary pack:p.getChilds()) {
//                    List<DeviceRetiredResultVo> d = childDeviceRetiredResultVo.getChilds();
//                    d.add(calcDeviceRetiredResultVo(pack));
//                    childDeviceRetiredResultVo.setChilds(d);
//                }
//            }
//            List<DeviceRetiredResultVo> d = childDeviceRetiredResultVo.getChilds();
//            d.add(childDeviceRetiredResultVo);
//            childDeviceRetiredResultVo.setChilds(d);
//        }
        return deviceRetiredResultVo;
    }

    /**
     * 将该列装下的所有装备生命周期都变更为退装
     *
     * @param packingId
     */
    public void changeDeviceToRetired(Integer packingId) {
        //生成装备查询VO
        DeviceLibrarySelectVo deviceLibrarySelectVo = new DeviceLibrarySelectVo();
        deviceLibrarySelectVo.setPackingId(packingId);
        //查询
        List<DeviceLibrary> list = deviceLibraryService.getList(deviceLibrarySelectVo);
        //遍历查询出来的list 将list中的每一件装备的状态都设置为退装
        list.forEach(d -> {
            d.setLifeStatus(8);
            deviceLibraryService.update(d);
            deviceLogService.addLog(new DeviceLogDto(d.getId(), "装备退装", null));
            //包括装备的配件也设置为退装
            List<DeviceLibrary> deviceChildren = d.getChilds();
            for (DeviceLibrary childDevice : deviceChildren) {
                childDevice.setLifeStatus(8);
                deviceLibraryService.update(childDevice);
                deviceLogService.addLog(new DeviceLogDto(childDevice.getId(), "装备退装", null));
            }
        });
    }

    private TaskBto initTaskBto(DeviceRetiredBill retiredBill) {
        //生成Task
        return new TaskBto(
                StatusEnum.END.id,
                "退装业务",
                0,
                ".",
                retiredBill.getId(),
                BusinessEnum.RETIRED.id,
                userUtils.getCurrentUnitId(),
                0,
                "",
                ListUtil.createList(retiredBill.getUserAId()));
    }

    /**
     * 筛选出可以退装的父子装备（父的所有子数量都为0）
     */
    private List<DeviceRetiredResultVo> canRetired(List<DeviceRetiredResultVo> deviceRetiredResultVos){
        List<DeviceRetiredResultVo> deviceRetiredResultVoList = new ArrayList<>();
        Map<Integer,DeviceRetiredResultVo> map = deviceRetiredResultVos.stream().collect(Collectors.toMap(DeviceRetiredResultVo::getId, Function.identity()));
        List<DeviceRetiredResultVo> retiredResultVos = deviceRetiredResultVos.stream()
                .filter(deviceRetiredResultVo -> deviceRetiredResultVo.getCount()==0&&(deviceRetiredResultVo.getPartParentId()==null||map.get(deviceRetiredResultVo.getPartParentId())==null))
                .collect(Collectors.toList());
        deviceRetiredResultVoList.addAll(retiredResultVos);
        if (retiredResultVos.size()>0) {
            deviceRetiredResultVos.removeAll(retiredResultVos);
            deviceRetiredResultVoList.addAll(canRetired(deviceRetiredResultVos));
        }
        return deviceRetiredResultVoList;
    }
}
