package com.sunyard.chsm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sunyard.chsm.dto.DeviceGroupDTO;
import com.sunyard.chsm.mapper.SpDeviceGroupMapper;
import com.sunyard.chsm.mapper.SpDeviceMapper;
import com.sunyard.chsm.model.entity.Device;
import com.sunyard.chsm.model.entity.DeviceGroup;
import com.sunyard.chsm.service.DeviceGroupService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author liulu
 * @since 2024/10/21
 */
@Slf4j
@Service("sp_DeviceGroupServiceImpl")
@Transactional
public class DeviceGroupServiceImpl implements DeviceGroupService {

    @Resource
    private SpDeviceMapper spDeviceMapper;
    @Resource
    private SpDeviceGroupMapper spDeviceGroupMapper;


    @Override
    public Page<DeviceGroupDTO.DGView> selectPageList(DeviceGroupDTO.Query query) {

        LambdaQueryWrapper<DeviceGroup> wrapper = new LambdaQueryWrapper<DeviceGroup>()
                .like(StringUtils.hasText(query.getName()), DeviceGroup::getName, query.getName())
                .orderByDesc(DeviceGroup::getCreateTime);

        IPage<DeviceGroup> page = spDeviceGroupMapper.selectPage(
                new Page<>(query.getPageNumber(), query.getPageSize()),
                wrapper);
        List<DeviceGroup> records = page.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        }

        List<Long> ids = records.stream().map(DeviceGroup::getId).collect(Collectors.toList());
        Map<Long, List<Device>> groupMap = spDeviceMapper.selectList(
                new LambdaQueryWrapper<Device>()
                        .in(Device::getGroupId, ids)
        ).stream().collect(Collectors.groupingBy(Device::getGroupId));

        List<DeviceGroupDTO.DGView> viewList = records.stream()
                .map(it -> {
                    DeviceGroupDTO.DGView view = new DeviceGroupDTO.DGView();
                    BeanUtils.copyProperties(it, view);

                    Map<Long, Device> deviceNames = groupMap.getOrDefault(it.getId(), Collections.emptyList())
                            .stream()
                            .collect(Collectors.toMap(Device::getId, Function.identity()));
                    List<Device> deviceList = deviceNames.entrySet()
                            .stream().map(entry -> {
                                Device d = new Device();
                                d.setId(entry.getKey());
                                d.setName(entry.getValue().getName());
                                d.setWeight(entry.getValue().getWeight());
                                return d;
                            }).collect(Collectors.toList());
                    view.setCheckedDevices(deviceList);
                    view.setDeviceNames(deviceList.stream().map(Device::getName).collect(Collectors.joining(",")));
                    return view;
                })
                .collect(Collectors.toList());

        return new Page<DeviceGroupDTO.DGView>(page.getCurrent(), page.getSize(), page.getTotal()).setRecords(viewList);

    }

    @Override
    public Long save(DeviceGroupDTO.DGSave save) {

        checkName(save.getName());

        DeviceGroup add = new DeviceGroup();
        add.setId(IdWorker.getId());
        add.setName(save.getName());
        add.setRemark(save.getRemark());
        add.setCreateTime(LocalDateTime.now());

        spDeviceGroupMapper.insert(add);

        // 设备和组关系绑定
        if (!CollectionUtils.isEmpty(save.getDeviceIds())) {
            LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<Device>()
                    .in(Device::getId, save.getDeviceIds());

            Device up = new Device();
            up.setGroupId(add.getId());
            up.setGroupName(save.getName());

            spDeviceMapper.update(up, wrapper);
        }

        return add.getId();
    }

    @Override
    public void update(DeviceGroupDTO.DGSave update) {
        Assert.notNull(update.getId(), "id不能为空");
        DeviceGroup exist = spDeviceGroupMapper.selectById(update.getId());
        Assert.notNull(exist, "id对应的设备组不存在");

        if (!Objects.equals(exist.getName(), update.getName())) {
            checkName(update.getName());
        }

        DeviceGroup upGroup = new DeviceGroup();
        upGroup.setId(update.getId());
        upGroup.setName(update.getName());
        upGroup.setRemark(update.getRemark());
        upGroup.setUpdateTime(LocalDateTime.now());
        spDeviceGroupMapper.updateById(upGroup);

        Device reset = new Device();
        reset.setGroupId(0L);
        reset.setGroupName("");
        reset.setWeight(1);
        LambdaQueryWrapper<Device> resetWrapper = new LambdaQueryWrapper<Device>()
                .eq(Device::getGroupId, update.getId());
        spDeviceMapper.update(reset, resetWrapper);
        // 设备和组关系绑定
        if (!CollectionUtils.isEmpty(update.getDeviceIds())) {
            LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<Device>()
                    .in(Device::getId, update.getDeviceIds());

            Device up = new Device();
            up.setGroupId(update.getId());
            up.setGroupName(update.getName());
            spDeviceMapper.update(up, wrapper);
        }

    }

    private void checkName(String name) {
        LambdaQueryWrapper<DeviceGroup> wrapper = new LambdaQueryWrapper<DeviceGroup>()
                .eq(DeviceGroup::getName, name);
        DeviceGroup exist = spDeviceGroupMapper.selectOne(wrapper);
        Assert.isNull(exist, "设备组名称已存在");
    }

    @Override
    public void updateLoadWeight(DeviceGroupDTO.LoadWeight loadWeight) {

        DeviceGroup exist = spDeviceGroupMapper.selectById(loadWeight.getId());
        Assert.notNull(exist, "id对应的设备组不存在");

        for (DeviceGroupDTO.WeightDe device : loadWeight.getDevices()) {
            Device up = new Device();
            up.setId(device.getId());
            up.setWeight(device.getWeight());
            spDeviceMapper.updateById(up);
        }

    }

    @Override
    public void delete(Long id) {
        Assert.notNull(id, "id不能为空");
        DeviceGroup exist = spDeviceGroupMapper.selectById(id);
        Assert.notNull(exist, "id对应的设备组不存在");

        LambdaQueryWrapper<Device> resetWrapper = new LambdaQueryWrapper<Device>()
                .eq(Device::getGroupId, id);
        Long count = spDeviceMapper.selectCount(resetWrapper);
        Assert.isTrue(count <= 0, "设备组存在设备, 不能删除");

        spDeviceGroupMapper.deleteById(id);

    }
}
