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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.pms.controller.admin.iotdeviceperson.vo.IotDevicePersonPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdeviceperson.vo.IotDevicePersonRelationSaveReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdeviceperson.vo.IotDevicePersonSaveReqVO;
import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdeviceperson.IotDevicePersonDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicepersonlog.IotDevicePersonLogDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicestatuslog.IotDeviceStatusLogDO;
import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotdeviceperson.IotDevicePersonMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotdevicepersonlog.IotDevicePersonLogMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotdevicestatuslog.IotDeviceStatusLogMapper;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
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_DEVICE_PERSON_NOT_EXISTS;
import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_DEVICE_STATUS_LOG_NOT_EXISTS;

/**
 * 设备负责人分配 Service 实现类
 *
 * @author ruiqi
 */
@Service
@Validated
public class IotDevicePersonServiceImpl implements IotDevicePersonService {

    @Resource
    private IotDevicePersonMapper iotDevicePersonMapper;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private IotDeviceStatusLogMapper iotDeviceStatusLogMapper;
    @Resource
    private IotDeviceMapper iotDeviceMapper;
    @Resource
    private IotDevicePersonLogMapper iotDevicePersonLogMapper;

    @Override
    public Long createIotDevicePerson(IotDevicePersonSaveReqVO createReqVO) {
        // 插入
        IotDevicePersonDO iotDevicePerson = BeanUtils.toBean(createReqVO, IotDevicePersonDO.class);
        iotDevicePersonMapper.insert(iotDevicePerson);
        // 返回
        return iotDevicePerson.getId();
    }

    @Override
    public void updateIotDevicePerson(IotDevicePersonSaveReqVO updateReqVO) {
        // 校验存在
        validateIotDevicePersonExists(updateReqVO.getId());
        // 更新
        IotDevicePersonDO updateObj = BeanUtils.toBean(updateReqVO, IotDevicePersonDO.class);
        iotDevicePersonMapper.updateById(updateObj);
    }

    @Override
    public void deleteIotDevicePerson(Long id) {
        // 校验存在
        validateIotDevicePersonExists(id);
        // 删除
        iotDevicePersonMapper.deleteById(id);
    }

    private void validateIotDevicePersonExists(Long id) {
        if (iotDevicePersonMapper.selectById(id) == null) {
            throw exception(IOT_DEVICE_PERSON_NOT_EXISTS);
        }
    }

    @Override
    public IotDevicePersonDO getIotDevicePerson(Long id) {
        return iotDevicePersonMapper.selectById(id);
    }

    @Override
    public PageResult<IotDevicePersonDO> getIotDevicePersonPage(IotDevicePersonPageReqVO pageReqVO) {
        return iotDevicePersonMapper.selectPage(pageReqVO);
    }

    @Override
    public Map<Long, String> getIotDevicePerson(Collection<Long> ids) {
        List<IotDevicePersonDO> devicePersons = iotDevicePersonMapper.selectDevicePersonList(ids, null);
        if (CollUtil.isEmpty(devicePersons)) {
            return new HashMap<>();
        }
        List<Long> personIds = new ArrayList<>();
        devicePersons.forEach(dp -> {
            personIds.add(dp.getPersonId());
        });
        // 查询人员ids 对应的人员姓名集合
        Map<Long, AdminUserRespDTO> users = adminUserApi.getUserMap(personIds);
        // 设备和人员姓名匹配集合
        Map<Long, String> devicePersonNames = new HashMap<>();
        for (IotDevicePersonDO devicePerson : devicePersons) {
            AdminUserRespDTO user = users.get(devicePerson.getPersonId());
            if (devicePersonNames.containsKey(devicePerson.getDeviceId())) {
                String tempNames = devicePersonNames.get(devicePerson.getDeviceId());
                Set<String> tempNameList = new HashSet<>(Arrays.asList(tempNames.split(",")));
                String currentUserName = ObjUtil.isEmpty(user) ? StrUtil.EMPTY : user.getNickname();
                tempNameList.add(currentUserName);
                devicePersonNames.put(devicePerson.getDeviceId(), StringUtils.join(tempNameList, ","));
            } else {
                devicePersonNames.put(devicePerson.getDeviceId(), ObjUtil.isEmpty(user) ? StrUtil.EMPTY : user.getNickname());
            }
        }
        return devicePersonNames;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveDevicePersons(List<IotDevicePersonRelationSaveReqVO> reqVOS) {
        if (CollUtil.isEmpty(reqVOS)) {
            throw exception(IOT_DEVICE_PERSON_NOT_EXISTS);
        }

        // 保存设备与人员的关联关系时，先删除再新增
        List<Long> deviceIds = new ArrayList<>();
        reqVOS.forEach(relation -> {
            deviceIds.add(relation.getDeviceId());
        });
        // 先查询出修改前的设备责任人
        List<IotDevicePersonDO> oldDevicePersons = iotDevicePersonMapper.selectList("device_id", deviceIds);
        // 把修改前的设备责任人 设置成 map<deviceId, personIds> 的格式
        Map<Long, List<Long>> oldDevicePersonPair = new HashMap<>();
        if (CollUtil.isNotEmpty(oldDevicePersons)) {
            oldDevicePersons.forEach(devicePerson -> {
                if (oldDevicePersonPair.containsKey(devicePerson.getDeviceId())) {
                    List<Long> tempPersons = oldDevicePersonPair.get(devicePerson.getDeviceId());
                    tempPersons.add(devicePerson.getPersonId());
                    oldDevicePersonPair.put(devicePerson.getDeviceId(), tempPersons);
                } else {
                    List<Long> tempPersons = new ArrayList<>();
                    tempPersons.add(devicePerson.getPersonId());
                    oldDevicePersonPair.put(devicePerson.getDeviceId(), tempPersons);
                }
            });
        }

        if (CollUtil.isNotEmpty(deviceIds)) {
            iotDevicePersonMapper.deleteByDeviceIds(deviceIds);;
        }
        List<IotDevicePersonDO> devicePersons = new ArrayList<>();
        reqVOS.forEach(relation -> {
            List<Long> userIds = relation.getUserIds();
            userIds.forEach(userId -> {
                IotDevicePersonDO devicePerson = new IotDevicePersonDO();
                devicePerson.setDeviceId(relation.getDeviceId());
                devicePerson.setPersonId(userId);
                devicePersons.add(devicePerson);
            });
        });
        // 批量保存 设备与 责任人的关联
        // 按 (deviceId, personId) 去重 ---
        Set<String> personKeySet = new HashSet<>();
        List<IotDevicePersonDO> distinctDevicePersons = devicePersons.stream()
                .filter(dp -> personKeySet.add(dp.getDeviceId() + "-" + dp.getPersonId()))
                .collect(Collectors.toList());
        iotDevicePersonMapper.insertBatch(distinctDevicePersons);
        // 记录设备责任人调整日志
        // 先查询保存之前的设备责任人
        // 将新的设备及责任人 设置成 map<deviceId, personIds> 格式
        Map<Long, List<Long>> newDevicePersonPair = new HashMap<>();
        Map<Long, String> deviceReasonPair = new HashMap<>();
        reqVOS.forEach(devicePerson -> {
            newDevicePersonPair.put(devicePerson.getDeviceId(), devicePerson.getUserIds());
            deviceReasonPair.put(devicePerson.getDeviceId(), devicePerson.getReason());
        });
        // 将修改前的设备责任人 修改后的设备责任人对应关系 存储到 责任人调整日志表
        List<IotDevicePersonLogDO> devicePersonLogDOS = new ArrayList<>();
        if (CollUtil.isNotEmpty(newDevicePersonPair)) {
            newDevicePersonPair.forEach((k,v) -> {
                // k设备id v设备关联的责任人集合
                IotDevicePersonLogDO devicePersonLog = new IotDevicePersonLogDO();
                devicePersonLog.setDeviceId(k);
                if (oldDevicePersonPair.containsKey(k)) {
                    List<Long> oldPersonIds = oldDevicePersonPair.get(k);
                    String oldPersonIdStrs = oldPersonIds.stream()
                            .map(String::valueOf)
                            .collect(Collectors.joining(","));
                    devicePersonLog.setOldPersonIds(oldPersonIdStrs);
                }
                if (newDevicePersonPair.containsKey(k)) {
                    List<Long> newPersonIds = newDevicePersonPair.get(k);
                    String newPersonIdStrs = newPersonIds.stream()
                            .map(String::valueOf)
                            .collect(Collectors.joining(","));
                    devicePersonLog.setNewPersonIds(newPersonIdStrs);
                }
                if (deviceReasonPair.containsKey(k)) {
                    devicePersonLog.setReason(deviceReasonPair.get(k));
                }
                devicePersonLogDOS.add(devicePersonLog);
            });
            if (CollUtil.isNotEmpty(devicePersonLogDOS)) {
                // 按 (deviceId, oldPersonIds, newPersonIds) 去重 ---
                Set<String> logKeySet = new HashSet<>();
                List<IotDevicePersonLogDO> distinctLogs = devicePersonLogDOS.stream()
                        .filter(log -> logKeySet.add(
                                log.getDeviceId() + "|" +
                                        Objects.toString(log.getOldPersonIds(), "") + "|" +
                                        log.getNewPersonIds()))
                        .collect(Collectors.toList());
                if (CollUtil.isNotEmpty(distinctLogs)) {
                    iotDevicePersonLogMapper.insertBatch(distinctLogs);
                }
            }
        }
        return 1l;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveDeviceStatuses(List<IotDevicePersonRelationSaveReqVO> reqVOS) {
        // 批量保存设备的状态
        if (CollUtil.isEmpty(reqVOS)) {
            throw exception(IOT_DEVICE_STATUS_LOG_NOT_EXISTS);
        }
        // 查询出所有要保存设备的id
        List<Long> deviceIds = new ArrayList<>();
        reqVOS.forEach(req -> {
            deviceIds.add(req.getDeviceId());
        });
        List<IotDeviceDO> devices = iotDeviceMapper.selectList("id", deviceIds);
        Map<Long, IotDeviceDO> deviceMap = devices.stream()
                .collect(Collectors.toMap(IotDeviceDO::getId, device -> device));
        // 如果调整前后 设备状态一样，则不向日志表中插入值
        List<IotDeviceStatusLogDO> deviceStatusLogs = new ArrayList<>();
        List<IotDeviceDO> tobeUpdatedDevices = new ArrayList<>();
        reqVOS.forEach(req -> {
            if (deviceMap.containsKey(req.getDeviceId()) && !req.getStatus().equals(deviceMap.get(req.getDeviceId()).getDeviceStatus())) {
                IotDeviceStatusLogDO tempDeviceStatus = new IotDeviceStatusLogDO();
                tempDeviceStatus.setDeviceId(req.getDeviceId());
                tempDeviceStatus.setOldStatus(deviceMap.get(req.getDeviceId()).getDeviceStatus());
                tempDeviceStatus.setNewStatus(req.getStatus());
                tempDeviceStatus.setReason(req.getReason());
                deviceStatusLogs.add(tempDeviceStatus);
                IotDeviceDO device = deviceMap.get(req.getDeviceId());
                device.setDeviceStatus(req.getStatus());
                tobeUpdatedDevices.add(device);
            }
        });
        // 批量插入设备状态 调整关联关系
        if (CollUtil.isNotEmpty(deviceStatusLogs)) {
            iotDeviceStatusLogMapper.insertBatch(deviceStatusLogs);
        }
        // 批量修改 设备的状态
        if (CollUtil.isNotEmpty(tobeUpdatedDevices)) {
            iotDeviceMapper.updateBatch(tobeUpdatedDevices);
        }
        return 1l;
    }

    @Override
    public List<IotDevicePersonDO> getPersonsByDeviceIds(IotDevicePersonPageReqVO pageReqVO) {
        Collection<Long> deviceIds = pageReqVO.getDeviceIds();
        if (CollUtil.isEmpty(deviceIds)) {
            throw exception(IOT_DEVICE_PERSON_NOT_EXISTS);
        }
        return iotDevicePersonMapper.selectDevicePersonList(deviceIds, null);
    }

    @Override
    public List<IotDevicePersonDO> getByPersonIds(IotDevicePersonPageReqVO pageReqVO) {
        Collection<Long> personIds = pageReqVO.getPersonIds();
        List<IotDevicePersonDO> result = new ArrayList<>();
        if (CollUtil.isNotEmpty(personIds)) {
            result = iotDevicePersonMapper.selectDevicePersonList(null, personIds);
        }
        return result;
    }

}