package com.bocloud.ims.service.utils;

import com.bocloud.entity.bean.Generic;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;


@Slf4j
public class SangforSyncHelper<T extends Generic> {

    private List<T> newlyList;
    private List<T> oldenList;
    private Function<T, Serializable> idGetter;

    private Consumer<List<T>> updateListConsumer;
    private Consumer<List<T>> insertListConsumer;
    private Consumer<Set<Serializable>> idRemoveConsumer;
    private Consumer<List<T>> removeListConsumer;


    public SangforSyncHelper(List<T> newlyList, List<T> oldList, Function<T, Serializable> idGetter) {
        this.newlyList = newlyList;
        this.oldenList = oldList;
        this.idGetter = idGetter;
    }

    public static <T extends Generic> SangforSyncHelper<T> build(List<T> newlyList, List<T> oldList, Function<T, Serializable> idGetter) {
        return new SangforSyncHelper<T>(newlyList, oldList, idGetter);
    }


    public SangforSyncHelper<T> whenUpdate(Consumer<List<T>> updateListConsumer) {
        this.updateListConsumer = updateListConsumer;
        return this;
    }

    public SangforSyncHelper<T> whenInsert(Consumer<List<T>> insertListConsumer) {
        this.insertListConsumer = insertListConsumer;
        return this;
    }


    public SangforSyncHelper<T> whenRemove(Consumer<List<T>> removeListConsumer) {
        this.removeListConsumer = removeListConsumer;
        return this;
    }

    public void sync() {
        T firstNewly;
        if (!oldenList.isEmpty()) {
            firstNewly = oldenList.stream().findFirst().get();
        } else if (!newlyList.isEmpty()) {
            firstNewly = newlyList.stream().findFirst().get();
        } else {
            return;
        }
        Class<?> aClass = firstNewly.getClass();
        log.info("开始同步：{}", aClass.getSimpleName());
        //通过ID映射数据
        Map<Serializable, T> oldenMap = this.oldenList.stream().collect(Collectors.toMap(idGetter, Function.identity(), (f, s) -> f, LinkedHashMap::new));
        Map<Serializable, T> newlyMap = this.newlyList.stream().collect(Collectors.toMap(idGetter, Function.identity(), (f, s) -> f, LinkedHashMap::new));

        Set<Serializable> oldenKeys = oldenMap. keySet();
        Set<Serializable> newlyKeys = newlyMap.keySet();

        //获取需要更新的数据, oldenMap中存在newlyMap中的key，则需要更新
        //获取需要新增的数据，newlyMap中不存在与oldenMap中的，则需要添加
        //获取需要删除的数据，oldenMap中不存在与newlyMap中的，则需要删除
        List<T> insertList = new ArrayList<>();
        List<T> updateList = new ArrayList<>();
        List<T> removeList = new ArrayList<>();

        oldenKeys.forEach(oldenKey -> {
            //旧key存在于新key中，则需要更新
            if (newlyKeys.contains(oldenKey)) {
                T olden = oldenMap.get(oldenKey);
                T newly = newlyMap.get(oldenKey);
                BeanUtils.copyPropertiesIgnoreNull(newly, olden);
                updateList.add(olden);
            } else {//不存在则需要删除
                removeList.add(oldenMap.get(oldenKey));
            }
        });

        newlyKeys.forEach(newlyKey -> {
            //旧key不包含则需要新增
            if (!oldenKeys.contains(newlyKey)) {
                insertList.add(newlyMap.get(newlyKey));
            }
        });

        if (!updateList.isEmpty() && updateListConsumer != null) {
            log.info("需要更新的数据：{}", updateList.size());
            updateListConsumer.accept(updateList);
        }
        if (!insertList.isEmpty() && insertListConsumer != null) {
            log.info("需要插入的数据：{}", insertList.size());
            insertListConsumer.accept(insertList);
        }
        if (!removeList.isEmpty() && removeListConsumer != null) {
            log.info("需要移除的数据：{}", insertList.size());
            removeListConsumer.accept(removeList);
        }
    }
}
