package cn.iocoder.yudao.module.system.controller.admin.positionmap;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.NodeTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.system.api.path.PathApi;
import cn.iocoder.yudao.module.system.controller.admin.log.vo.UserOperationLogSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.dto.NodeBaseDTO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.dto.PositionMapConfigDTO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.dto.PositionMapItemNodeDTO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapItemRespVO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapItemSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapLineSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapItemDO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapLineDO;
import cn.iocoder.yudao.module.system.enums.robot.task.event.EventTypeEnum;
import cn.iocoder.yudao.module.system.handler.mapnode.NodeProcessingContext;
import cn.iocoder.yudao.module.system.mq.message.map.MapMessage;
import cn.iocoder.yudao.module.system.mq.producer.map.MapProducer;
import cn.iocoder.yudao.module.system.service.log.UserOperationLogService;
import cn.iocoder.yudao.module.system.service.positionmap.PositionMapItemService;
import cn.iocoder.yudao.module.system.service.positionmap.PositionMapLineService;
import cn.iocoder.yudao.module.system.service.robot.RobotTaskService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

@Slf4j
@Tag(name = "管理后台 - 仓库点位地图子表")
@RestController
@RequestMapping("/system/position-map-item")
@Validated
public class PositionMapItemController {

    @Resource
    private PositionMapItemService positionMapItemService;

    @Resource
    private NodeProcessingContext nodeProcessingContext;

    @Resource
    private UserOperationLogService userOperationLogService;

    @Resource
    private PositionMapLineService positionMapLineService;

    @Resource
    private RobotTaskService taskService;

    @Resource
    private MapProducer mapProducer;

    // -- 前端给所有的节点信息 -
    @PostMapping("/batchSaveOrEditOrDel")
    @Operation(summary = "批量新增编辑删除节点")
    public CommonResult<Boolean> batchSaveOrEditOrDel(@RequestParam Long positionMapId, @Valid @RequestBody List<NodeBaseDTO> nodeBaseDTOS) {
        //校验是否存在未完成的任务
        taskService.checkHaveDoingTask();
        // -- 这里使用策略模式 - 根据各个类型区分 - 如果需要新增类型，新增策略实现类即可 - 如果不需要关联存储具体的表，直接将json存储到dataJson字段即可
        Map<Integer, List<NodeBaseDTO>> map = nodeBaseDTOS.stream().collect(Collectors.groupingBy(NodeBaseDTO::getType));
        // -- 获取到对应地图的所有点位
        List<PositionMapItemDO> oldList = positionMapItemService.getByMapId(positionMapId);
        List<PositionMapItemDO> newAllList = new ArrayList<>();
        for (Integer key : NodeTypeEnum.getAllTypes()) {
            List<NodeBaseDTO> nodeBaseDTOList = CollectionUtil.isEmpty(map.get(key)) ? Collections.emptyList() : map.get(key);
            List<PositionMapItemDO> newList = nodeProcessingContext.processNodesByStrategy(positionMapId, key, nodeBaseDTOList);
            newAllList.addAll(newList);
        }
        List<List<PositionMapItemDO>> list = CollectionUtils.compareLists(oldList, newAllList,
                (oldVal, newVal) -> ObjectUtil.equal(oldVal.getId(), newVal.getId()));
        positionMapItemService.batchSaveOrEditOrDel(positionMapId, list);

        UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder()
                .operateAction("保存地图编辑")
                .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
        userOperationLogService.createUserOperationLog(operationLog);

        MapMessage mes = new MapMessage(this, positionMapId + "",
                EventTypeEnum.MAP_UPDATE.getType());
        mapProducer.sendSmsSendMessage(mes);

        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得仓库点位地图子表")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('system:position-map-item:query')")
    public CommonResult<PositionMapItemRespVO> getPositionMapItem(@RequestParam("id") Long id) {
        PositionMapItemDO positionMapItem = positionMapItemService.getPositionMapItem(id);
        return success(BeanUtils.toBean(positionMapItem, PositionMapItemRespVO.class));
    }

    @GetMapping("/getAGVPointInformation")
    @Operation(summary = "获取AGV点位信息")
    @Parameter(name = "macAddress", description = "mac地址", required = true, example = "1024")
    public CommonResult<Object> getAGVPointInformation(@RequestParam("macAddress") String macAddress) {
        Object object = positionMapItemService.getAGVPointInformation(macAddress);
        return success(object);
    }

    @GetMapping("/list")
    @Operation(summary = "获取仓库点位地图节点列表")
    @PreAuthorize("@ss.hasPermission('system:position-map-item:query')")
    public CommonResult<List<PositionMapItemRespVO>> getPositionMapItemPage(@RequestParam("positionMapId") Long positionMapId,
                                                                            @RequestParam(value = "areaId", required = false) Long areaId,
                                                                            @RequestParam(value = "laneId", required = false) Long laneId) {
        List<PositionMapItemDO> list = positionMapItemService.list(new LambdaQueryWrapperX<PositionMapItemDO>()
                .eq(PositionMapItemDO::getPositionMapId, positionMapId)
                .eqIfPresent(PositionMapItemDO::getAreaId, areaId)
                .eqIfPresent(PositionMapItemDO::getLaneId, laneId));
        return success(BeanUtils.toBean(list, PositionMapItemRespVO.class));
    }

    @GetMapping("/getUUid")
    @Operation(summary = "获取id")
    @PreAuthorize("@ss.hasPermission('system:position-map-item:getUUid')")
    public CommonResult<Long> getUUid() {
        Long id = positionMapItemService.getUUid();
        return success(id);
    }

    @PostMapping("/lineAddItem")
    @Operation(summary = "线上加点保存点位")
    @PreAuthorize("@ss.hasPermission('system:position-map-item:lineAddItem')")
    public CommonResult<Map<String, Object>> lineAddItem(@Valid @RequestBody List<PositionMapItemNodeDTO> list) {

        PositionMapItemSaveReqVO positionMapItem = BeanUtils.toBean(list.get(0), PositionMapItemSaveReqVO.class);
        positionMapItemService.createPositionMapItem(positionMapItem);

        positionMapLineService.deletePositionMapLine(list.get(0).getOldLineId());
        List<PositionMapLineSaveReqVO> positionMapLines = list.get(0).getPositionMapLines();
        List<PositionMapLineDO> lineList = BeanUtils.toBean(positionMapLines, PositionMapLineDO.class);
        List<Long> itemIds = new ArrayList<>();
        for (PositionMapLineDO positionMapLineDO : lineList) {
            itemIds.add(positionMapLineDO.getStartingPointId());
            itemIds.add(positionMapLineDO.getEndPointId());
        }

        Map<Long, Long> sortNumMap = positionMapItemService.getSortNumMapByIds(itemIds);

        for (PositionMapLineDO positionMapLineDO : lineList) {
            positionMapLineDO.setPositionMapId(positionMapItem.getPositionMapId());
            positionMapLineDO.setStartingSortNum(sortNumMap.get(positionMapLineDO.getStartingPointId()).intValue());
            positionMapLineDO.setEndPointSortNum(sortNumMap.get(positionMapLineDO.getEndPointId()).intValue());
        }
        positionMapLineService.batchSaveLines(lineList);
        Map<String, Object> map = new HashMap<>();
        map.put("ITEM", positionMapItemService.getPositionMapItem(positionMapItem.getId()));
        map.put("LINE", lineList);
        return success(map);
    }

    @GetMapping("/getCheckDistance")
    @Operation(summary = "获取检测点距离")
    @PreAuthorize("@ss.hasPermission('system:position-map-item:getCheckDistance')")
    public CommonResult<PositionMapConfigDTO> getCheckDistance() {
        PositionMapConfigDTO distance = positionMapItemService.getCheckDistance();
        return success(distance);
    }
}
