package com.ruoyi.system.service.impl;

import com.ruoyi.common.biz.BaseServiceImpl;
import com.ruoyi.system.domain.SysDevice;
import com.ruoyi.system.mapper.SysDevicePropertyMapper;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.domain.SysDeviceProperty;
import com.ruoyi.system.service.ISysDevicePropertyService;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import javax.annotation.Resource;
import javax.validation.constraints.Null;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 设备属性Service业务层处理
 *
 * @author ruoyi
 * @date 2023-08-17
 */
@Service
public class SysDevicePropertyServiceImpl
        extends BaseServiceImpl<SysDeviceProperty, Long, SysDevicePropertyMapper>
        implements ISysDevicePropertyService {

    /**
     * 新增设备属性
     *
     * @param sysDeviceProperty 设备属性
     * @return 结果
     */
    @Transactional
    @Override
    public Mono<Long> insert(SysDeviceProperty sysDeviceProperty) {
        return mapper.insert(sysDeviceProperty);
    }

    /**
     * 修改设备属性
     *
     * @param sysDeviceProperty 设备属性
     * @return 结果
     */
    @Transactional
    @Override
    public Mono<Long> update(SysDeviceProperty sysDeviceProperty) {
        return mapper.update(sysDeviceProperty);
    }

    @Override
    public Mono<Void> sync(SysDevice device, List<SysDeviceProperty> properties,String funcId) {
        SysDeviceProperty query = new SysDeviceProperty();
        query.setFuncId(funcId);
        query.setDeviceType(device.getDeviceType());
        return mapper.selectList(query).collectList().flatMap(list -> {
            List<SysDeviceProperty> writeList = new ArrayList<>();
            List<SysDeviceProperty> updateList = new ArrayList<>();
            for (SysDeviceProperty property : properties) {
                List<SysDeviceProperty> collect = list.stream().filter(x -> x.getName().equals(property.getName())).collect(Collectors.toList());
                if (collect.size() == 0) {
                    writeList.add(property);
                } else {
                    if (!collect.get(0).getValue().equals(property.getValue())) {
                        collect.get(0).setValue(property.getValue());
                        updateList.add(collect.get(0));
                    }
                }
            }
            if (writeList.size() != 0) {
                return Mono.defer(() -> {
                    // 使用 flatMapSequential 保证插入操作的顺序
                    return Flux.fromIterable(writeList)
                            .flatMapSequential(property -> Mono.fromRunnable(() -> mapper.insert(property).subscribe())
                                    .subscribeOn(Schedulers.boundedElastic()))
                            .then();
                }).thenReturn(list);
            }
            if (updateList.size() != 0) {
                return Mono.defer(() -> {
                    // 使用 flatMapSequential 保证插入操作的顺序
                    return Flux.fromIterable(updateList)
                            .flatMapSequential(property -> Mono.fromRunnable(() -> mapper.update(property).subscribe())
                                    .subscribeOn(Schedulers.boundedElastic()))
                            .then();
                }).thenReturn(list);
            }
            return Mono.just(list);
        }).switchIfEmpty(this.batchInstall(properties)).then(Mono.empty());

    }

    public Mono<List<SysDeviceProperty>> batchInstall(List<SysDeviceProperty> properties) {
        return Mono.defer(() -> {
            // 使用 flatMapSequential 保证插入操作的顺序
            return Flux.fromIterable(properties)
                    .flatMapSequential(property -> Mono.fromRunnable(()
                                    -> mapper.insert(property).subscribe())
                            .subscribeOn(Schedulers.boundedElastic()))
                    .then();
        }).thenReturn(properties);
    }
}
