package cn.iocoder.yudao.module.pms.service.inspect;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.pms.constant.PmsConstants;
import cn.iocoder.yudao.module.pms.controller.admin.inspect.order.vo.IotInspectOrderDetailPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.inspect.order.vo.IotInspectOrderPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.inspect.order.vo.IotInspectOrderSaveReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.inspect.route.vo.IotInspectRouteRespVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdeviceperson.vo.IotDevicePersonPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDevicePageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceSimple;
import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.*;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdeviceperson.IotDevicePersonDO;
import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.inspect.*;
import cn.iocoder.yudao.module.pms.message.PmsMessage;
import cn.iocoder.yudao.module.pms.service.IotDeviceService;
import cn.iocoder.yudao.module.pms.service.iotdeviceperson.IotDevicePersonService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_INSPECT_ORDER_DETAIL_NOT_EXISTS;
import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_INSPECT_ORDER_NOT_EXISTS;

/**
 * 巡检工单 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class IotInspectOrderServiceImpl implements IotInspectOrderService {

    @Resource
    private IotInspectOrderMapper iotInspectOrderMapper;
    @Autowired
    private IotInspectOrderDetailMapper iotInspectOrderDetailMapper;
    @Resource
    private DeptService deptService;
    @Resource
    private AdminUserApi adminUserApi;
    @Autowired
    private IotInspectItemMapper iotInspectItemMapper;
    @Autowired
    private IotDeviceMapper iotDeviceMapper;
    @Resource
    private IotInspectPlanMapper iotInspectPlanMapper;
    @Autowired
    private IotDevicePersonService iotDevicePersonService;
    @Resource
    private PmsMessage pmsMessage;
    @Autowired
    private IotDeviceService iotDeviceService;
    @Autowired
    private DeptApi deptApi;
    @Autowired
    private IotInspectOrderDeviceMapper iotInspectOrderDeviceMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void writeInspectOrderDetail(Map<String, String> requestMap, Long orderId) {
        String ifNormal = requestMap.get("ifNormal");
        String description = requestMap.get("description");
        String picUrl = requestMap.get("picUrl");
        String deviceId = requestMap.get("deviceId");
        String indexId = requestMap.get("indexId");
        IotInspectOrderDO order = iotInspectOrderMapper.selectById(orderId);
        if (Objects.isNull(order)){
            throw exception(IOT_INSPECT_ORDER_NOT_EXISTS);
        }
        List<IotInspectOrderDetailDO> details = iotInspectOrderDetailMapper.selectByMap(ImmutableMap.of("order_id", orderId, "device_id", deviceId, "index_id", Long.valueOf(indexId)));
        if (CollUtil.isEmpty(details)){
            throw exception(IOT_INSPECT_ORDER_DETAIL_NOT_EXISTS);
        }
        IotInspectOrderDetailDO detailDO = details.get(0);
        detailDO.setIfNormal("true".equals(ifNormal));
        detailDO.setDescription(description);
        detailDO.setPicUrl(picUrl);
        detailDO.setUpdateTime(LocalDateTime.now());
        iotInspectOrderDetailMapper.updateById(detailDO);

        Long deptId = SecurityFrameworkUtils.getLoginUserDeptId();
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(deptId)) {
            ids = deptService.getChildDeptIdListFromCache(deptId);
            ids.add(deptId);
        }
        Set<Long> collect = iotDeviceMapper.selectSimpleList(new IotDevicePageReqVO(), ids).stream().map(IotDeviceDO::getId).collect(Collectors.toSet());
        List<IotInspectOrderDetailDO> orderId1 = iotInspectOrderDetailMapper.selectList("order_id", orderId).stream().filter(e -> collect.contains(e.getDeviceId())).collect(Collectors.toList());
        boolean ma = orderId1.stream().anyMatch(f -> Objects.isNull(f.getIfNormal()));
        if (!ma) {
            order.setStatus("finished");
            order.setExecuteDate(LocalDateTime.now());
        }
        //填写巡检工单，更新异常等数目----------------------------------------
        List<IotInspectOrderDetailDO> detailss = iotInspectOrderDetailMapper.selectList("order_id", orderId);
        long deviceCount = detailss.stream().map(IotInspectOrderDetailDO::getDeviceId).distinct().count();
        long exceptionCount = detailss.stream().filter(f -> Objects.nonNull(f.getIfNormal()) && !f.getIfNormal()).map(IotInspectOrderDetailDO::getDeviceId).distinct().count();
        Map<Long, List<IotInspectOrderDetailDO>> collect11 = detailss.stream().collect(Collectors.groupingBy(IotInspectOrderDetailDO::getDeviceId));
        AtomicInteger needDevice = new AtomicInteger();
        collect11.forEach((k, v) -> {
            if (v.stream().anyMatch(gg -> Objects.isNull(gg.getIfNormal()))){
                needDevice.getAndIncrement();
            }
        });
        order.setDeviceCount(Math.toIntExact(deviceCount));
        order.setExceptionCount(Math.toIntExact(exceptionCount));
        order.setNeedDevice(needDevice.get());
        iotInspectOrderMapper.updateById(order);
        //--------------------------------------------------------------------------------------------------------
        CompletableFuture.runAsync(()->{
            //处理多责任人工单逻辑
            //判断该设备是否多个责任人
            Map<Long, String> iotDevicePerson = iotDevicePersonService.getIotDevicePerson(ImmutableList.of(Long.valueOf(deviceId)));
            String person = iotDevicePerson.get(Long.valueOf(deviceId));
            if (StringUtils.isNotBlank(person)) {
                String[] persons = person.split(",");
                //多个责任人的处理
                if (persons.length>1) {
                    //查询出该工单的该设备的所有巡检项
                    List<IotInspectOrderDetailDO> detailDOS = iotInspectOrderDetailMapper.selectByMap(ImmutableMap.of("order_id", orderId, "device_id", deviceId));
                    boolean allFinish = detailDOS.stream().noneMatch(e -> Objects.isNull(e.getIfNormal()));
                    //如果该工单该设备都巡检完成
                    if (allFinish) {
                        //查询所有当天的该设备的巡检明细
                        IotInspectOrderDetailDO todayDetail = detailDOS.get(0);
                        LocalDateTime createTime = todayDetail.getCreateTime();
                        String create = DateUtil.format(createTime, DatePattern.NORM_DATE_PATTERN);
                        LocalDateTime startOfDay = DateUtils.getStartOfDay(create);
                        LocalDateTime endOfDay = DateUtils.getEndOfDay(create);
                        IotInspectOrderDetailPageReqVO iotInspectOrderDetailPageReqVO = new IotInspectOrderDetailPageReqVO();
                        iotInspectOrderDetailPageReqVO.setCreateTime(new LocalDateTime[]{startOfDay, endOfDay});
                        iotInspectOrderDetailPageReqVO.setDeviceId(Long.valueOf(deviceId));
                        List<IotInspectOrderDetailDO> deviceIdDetails = iotInspectOrderDetailMapper.selectByTimeAndOrderIdAndDeviceId(iotInspectOrderDetailPageReqVO);
                        Map<Long, List<IotInspectOrderDetailDO>> otherOrderMap = deviceIdDetails.stream().filter(e -> !orderId.equals(e.getOrderId())).collect(Collectors.groupingBy(IotInspectOrderDetailDO::getOrderId));
                        otherOrderMap.forEach((k, v) -> {
//                            iotInspectOrderDetailPageReqVO.setDeviceId(null);
//                            iotInspectOrderDetailPageReqVO.setOrderId(k);
//                            List<IotInspectOrderDetailDO> orderIdDetails = iotInspectOrderDetailMapper.selectByTimeAndOrderIdAndDeviceId(iotInspectOrderDetailPageReqVO);
                            Map<Long, List<IotInspectOrderDetailDO>> collect1 = v.stream().collect(Collectors.groupingBy(IotInspectOrderDetailDO::getDeviceId));
                            //删除巡检明细
                            v.forEach(f -> iotInspectOrderDetailMapper.deleteById(f));
                            //如果工单里面只有这一个设备的话,删除该工单
//                            if (v.size()==orderIdDetails.size()) {
                            if (collect1.size()==1) {
                                iotInspectOrderMapper.deleteById(k);
                            }

                        });
                    }
                }
            }
        });
    }

    @Override
    public Long createIotInspectOrder(IotInspectOrderSaveReqVO createReqVO) {
        // 插入
        IotInspectOrderDO iotInspectOrder = BeanUtils.toBean(createReqVO, IotInspectOrderDO.class);
        iotInspectOrderMapper.insert(iotInspectOrder);
        // 返回
        return iotInspectOrder.getId();
    }

    @Override
    public void updateIotInspectOrder(IotInspectOrderSaveReqVO updateReqVO) {
        // 校验存在
        validateIotInspectOrderExists(updateReqVO.getId());
        // 更新
        IotInspectOrderDO updateObj = BeanUtils.toBean(updateReqVO, IotInspectOrderDO.class);
        iotInspectOrderMapper.updateById(updateObj);
    }

    @Override
    public void deleteIotInspectOrder(Long id) {
        // 校验存在
        validateIotInspectOrderExists(id);
        // 删除
        iotInspectOrderMapper.deleteById(id);
    }

    private void validateIotInspectOrderExists(Long id) {
        if (iotInspectOrderMapper.selectById(id) == null) {
            throw exception(IOT_INSPECT_ORDER_NOT_EXISTS);
        }
    }

    @Override
    public IotInspectOrderDO getIotInspectOrder(Long id) {
        return iotInspectOrderMapper.selectById(id);
    }

    @Override
    public PageResult<IotInspectOrderDO> getIotInspectOrderPage(IotInspectOrderPageReqVO pageReqVO) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        return iotInspectOrderMapper.selectPage(pageReqVO, ids, pageReqVO.getIdList());
    }

    @Override
    public PageResult<IotInspectOrderDO> getIotInspectOrderPageApp(IotInspectOrderPageReqVO pageReqVO) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        return iotInspectOrderMapper.selectPageApp(pageReqVO, ids, pageReqVO.getIdList());
    }

    /**
     * 设备调拨同步修改巡检工单的部门id及明细信息
     * @param deviceIds 设备id集合
     * @param deptId 调拨后的部门id
     */
    @Override
    public void syncWordOrderData(List<Long> deviceIds, Long deptId) {
        deviceIds.forEach(deviceId -> {
            List<IotInspectOrderDetailDO> deviceId1 = iotInspectOrderDetailMapper.selectList("device_id", deviceId);
            Map<Long, List<IotInspectOrderDetailDO>> collect = deviceId1.stream().collect(Collectors.groupingBy(IotInspectOrderDetailDO::getOrderId));
            collect.forEach((k,v)->{
                IotInspectOrderDO iotInspectOrderDO = iotInspectOrderMapper.selectById(k);
                //已完成
                if ("finished".equals(iotInspectOrderDO.getStatus())){
                    IotInspectOrderDO orderDO = new IotInspectOrderDO();
                    BeanUtils.copyProperties(iotInspectOrderDO, orderDO);
                    iotInspectOrderDO.setDeptId(deptId);
                    orderDO.setId(null);
                    iotInspectOrderMapper.insert(orderDO);
                    v.forEach(order -> {
                        order.setDeptId(deptId);
                        order.setOrderId(orderDO.getId());
                    });
                    iotInspectOrderDetailMapper.updateBatch(v);
                }
            });

        });

    }


    @Transactional(rollbackFor = Exception.class)
    public void createPlan(IotInspectPlanDO iotInspectPlan)  {
        Map<Long, List<IotInspectRouteRespVO>> generate = generate(iotInspectPlan.getDeviceIds());
        List<IotDeviceSimple> iotDeviceDOS = iotDeviceMapper.selectCodeAndNameList();
        generate.forEach((k, v)->{
            List<IotInspectOrderDetailDO> results = new ArrayList<>();
            //处理巡检项
            List<IotInspectItemDO> items = iotInspectItemMapper.selectList();
            v.forEach(routeDO -> {
                List<Map> itemos = JSON.parseArray(routeDO.getItemJson(), Map.class);
                for (Map item : itemos) {
                    Long deviceId = routeDO.getDeviceId();
                    IotDeviceDO deviceDO = iotDeviceMapper.selectById(deviceId);
                    if (Objects.nonNull(deviceDO)&&"sg".equals(deviceDO.getDeviceStatus())){
                        //如果部门id没调拨过
                        if (deviceDO.getDeptId().equals(routeDO.getDeptId())){
                            IotInspectOrderDetailDO detailDO = new IotInspectOrderDetailDO();
                            //detailDO.setOrderId(iotInspectOrderDO.getId());
                            detailDO.setDeviceId(routeDO.getDeviceId());
                            detailDO.setRouteId(routeDO.getId());
                            detailDO.setItemId(Objects.isNull(item.get("itemId"))?null:Long.valueOf(String.valueOf(item.get("itemId"))));
                            if (Objects.isNull(detailDO.getItemId())) {
                                System.out.println("---------------");
                            }
                            detailDO.setIndexId(Long.valueOf(String.valueOf(item.get("index"))));
                            detailDO.setDeleted(false);
                            detailDO.setIgnoreReason(false);
                            detailDO.setRouteIndex(routeDO.getIndex());
                            items.stream().filter(e -> e.getId().equals(detailDO.getItemId())).findFirst().ifPresent(iotItem->{
                                detailDO.setStandard(iotItem.getStandard());
                                detailDO.setUrls(iotItem.getUrls());
                                detailDO.setItem(iotItem.getItem());
                            });
                            //没有巡检项的话直接不生成
                            if (StringUtils.isBlank(detailDO.getStandard())){
                                continue;
                            }
                            IotDeviceDO iotDeviceDO = iotDeviceMapper.selectById(routeDO.getDeviceId());
                            if (Objects.nonNull(iotDeviceDO)){
                                detailDO.setDeptId(iotDeviceDO.getDeptId());
                            }
                            if (Objects.isNull(detailDO.getItemId())) {
                                System.out.println("1111");
                            }
                            results.add(detailDO);
                        }
                    }
                }
            });
            if (CollUtil.isEmpty(results)){
                return;
            }

            IotInspectOrderDO iotInspectOrderDO = new IotInspectOrderDO();
            AdminUserRespDTO user = adminUserApi.getUser(k);
            String deptName = "";
            String chinese = "";
            String english = "";
            if (Objects.nonNull(user)&&Objects.nonNull(user.getDeptId())) {
                DeptRespDTO dept = deptApi.getDept(user.getDeptId());
                if (Objects.nonNull(dept)) {
                    deptName = dept.getName();
                    if (StringUtils.isNotBlank(deptName)) {
                        String[] split = deptName.split("~~");
                        chinese = split[0];
                        if (split.length > 1) {
                            english = split[1];
                            if (StringUtils.isBlank(english)) {
                                english = chinese;
                            } else {
                                english = english.replace("en**", "");
                            }
                        }else {
                            english = chinese;
                        }
                    }
                }
            }
            String chineseName = chinese+"/"+(Objects.nonNull(user)?user.getNickname():"")+"/"+ DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd")+"-巡检工单";
            String englishName = english+"/"+(Objects.nonNull(user)?user.getNickname():"")+"/"+ DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd")+"-inspect order";
            iotInspectOrderDO.setInspectOrderTitle(chineseName+"~~en**"+englishName);
            iotInspectOrderDO.setInspectOrderCode("IN"+ DateUtil.format(new Date(),"yyyyMMddHHmmss")+UUID.randomUUID().toString().substring(0, 4));
            iotInspectOrderDO.setCharge(k);
            iotInspectOrderDO.setStatus("todo");
            iotInspectOrderDO.setType("计划生成");
            iotInspectOrderDO.setPlanCode(iotInspectPlan.getPlanCode());
            iotInspectOrderDO.setDeleted(false);
            iotInspectOrderDO.setChargeName(Objects.nonNull(user)?user.getNickname():"");
            iotInspectOrderDO.setDeptId(user.getDeptId());
            Set<Long> collect = results.stream().map(IotInspectOrderDetailDO::getDeviceId).collect(Collectors.toSet());
            iotInspectOrderDO.setDeviceCount(collect.size());
            iotInspectOrderDO.setNeedDevice(collect.size());
            iotInspectOrderDO.setExceptionCount(0);
            TenantUtils.execute(1L, () -> iotInspectOrderMapper.insert(iotInspectOrderDO));
            results.forEach(result-> result.setOrderId(iotInspectOrderDO.getId()));
            TenantUtils.execute(1L, () -> {
                iotInspectOrderDetailMapper.insertBatch(results);
                LocalDateTime localDateTime = DateUtils.contactTime(iotInspectPlan.getBeginCreateTime());
                iotInspectPlan.setLastCreateTime(localDateTime);
                iotInspectPlanMapper.updateById(iotInspectPlan);
            });
            CompletableFuture.runAsync(()->{
                //发送消息
                pmsMessage.sendMessage(iotInspectOrderDO.getId(), iotInspectOrderDO.getInspectOrderTitle(), PmsConstants.GENERATE_INSPECT, k, user.getMobile());
                //写入子表
//                Set<Long> collect = results.stream().map(IotInspectOrderDetailDO::getDeviceId).collect(Collectors.toSet());
                List<IotInspectOrderDeviceDO> inspectDevices = new ArrayList<>();
                collect.forEach(deviceId -> iotDeviceDOS.stream().filter(g -> deviceId.equals(g.getId())).findFirst().ifPresent(iotDeviceDO -> {
                    IotInspectOrderDeviceDO iotInspectOrderDeviceDO = new IotInspectOrderDeviceDO();
                    iotInspectOrderDeviceDO.setDeviceId(deviceId);
                    iotInspectOrderDeviceDO.setOrderId(iotInspectOrderDO.getId());
                    iotInspectOrderDeviceDO.setDeviceName(iotDeviceDO.getDeviceName());
                    iotInspectOrderDeviceDO.setDeptId(iotInspectOrderDO.getDeptId());
                    iotInspectOrderDeviceDO.setDeviceCode(iotDeviceDO.getDeviceCode());
                    iotInspectOrderDeviceDO.setDeleted(false);
                    inspectDevices.add(iotInspectOrderDeviceDO);
                }));
                TenantUtils.execute(1L, () -> iotInspectOrderDeviceMapper.insertBatch(inspectDevices));
            });
        });
    }

    private Map<Long, List<IotInspectRouteRespVO>> generate(String deviceIds) {
        List<IotInspectRouteRespVO> routeDOS = JSON.parseArray(deviceIds, IotInspectRouteRespVO.class);

        Map<Long, List<IotInspectRouteRespVO>> personToDevices = new HashMap<>();

        for (IotInspectRouteRespVO routeDO : routeDOS) {
            IotDevicePersonPageReqVO iotDevicePersonPageReqVO = new IotDevicePersonPageReqVO();
            if (routeDO==null||Objects.isNull(routeDO.getDeviceId())) {
                System.out.println("routedo---------------------------------------"+deviceIds);
                continue;
            }
            iotDevicePersonPageReqVO.setDeviceIds(ImmutableList.of(routeDO.getDeviceId()));
            List<IotDevicePersonDO> persons = iotDevicePersonService.getPersonsByDeviceIds(iotDevicePersonPageReqVO);
            for (IotDevicePersonDO person : persons) {
                personToDevices.computeIfAbsent(person.getPersonId(), k -> new ArrayList<>())
                        .add(routeDO);
            }
        }
        return personToDevices;
    }
}
