package com.bocloud.ims.service.common;

import java.util.ArrayList;
import java.util.List;

/**
 * 该类用来实现平台某个数据类型的同步
 *
 * @param <Model>  driver返回的model数据类型
 * @param <Entity> db中对应的entity数据类型
 */
public abstract class AbstractVendorSync<Model, Entity> {

    /**
     * 按平台id查询该资源列表
     *
     * @param vendorId 平台id
     */
    protected abstract List<Entity> listByVendor(long vendorId) throws Exception;

    /**
     * 保存entity
     *
     * @param entity entity
     * @param userId 当前用户id
     */
    protected abstract void save(Entity entity, long userId) throws Exception;

    /**
     * 更新entity
     *
     * @param entity entity
     * @param userId 当前用户id
     */
    protected abstract void update(Entity entity, long userId) throws Exception;

    /**
     * 删除entity，级联删除子资源，删的彻底
     *
     * @param entity entity
     * @param userId 当前用户id
     */
    public abstract void remove(Entity entity, long userId) throws Exception;


    /**
     * 将model转换成entity
     *
     * @param model    driver返回的model数据
     * @param entity   db中对应的entity数据
     * @param vendorId 该数据类型业务上的父数据的id
     */
    protected abstract void modelToEntity(Model model, Entity entity, long vendorId) throws Exception;

    /**
     * 在同一个平台下，判断一个model和一个entity在业务上是否为同一个数据
     *
     * @param model  driver返回的model数据类型
     * @param entity db中对应的entity数据
     * @return true 是 false 否
     */
    protected abstract boolean modelEqualEntity(Model model, Entity entity) throws Exception;

    /**
     * 根据model插入或更新一个entity
     *
     * @param modelClass  driver返回的model数据类型
     * @param entityClass db中对应的entity数据类型
     * @param vendorId    该数据类型业务上的父数据的id
     * @param model       driver返回的model数据
     * @param userId      当前用户id
     * @return 返回创建或更新后的entity
     */
    public Entity syncOne(Class<Model> modelClass, Class<Entity> entityClass, long vendorId, Model model, long userId) throws Exception {
        Entity entityFromDB = null;
        List<Entity> entities = listByVendor(vendorId);
        for (Entity entity : entities) {
            if (modelEqualEntity(model, entity)) {
                entityFromDB = entity;
                break;
            }
        }
        if (entityFromDB == null) {
            entityFromDB = entityClass.newInstance();
            modelToEntity(model, entityFromDB, vendorId);
            save(entityFromDB, userId);
        } else {
            modelToEntity(model, entityFromDB, vendorId);
            update(entityFromDB, userId);
        }
        return entityFromDB;
    }

    /**
     * 根据model对entity进行全面更新
     *
     * @param modelClass  driver返回的model数据类型
     * @param entityClass db中对应的entity数据类型
     * @param vendorId    该数据类型业务上的父数据的id
     * @param models      driver返回的model数据集合
     * @param userId      当前用户id
     * @return 返回创建或更新后的entity集合
     */
    public List<Entity> syncAll(Class<Model> modelClass, Class<Entity> entityClass, long vendorId, List<Model> models, long userId) throws Exception {
        List<Entity> result = new ArrayList<>();

        List<Entity> allEntities = listByVendor(vendorId);
        List<Entity> existsEntites = new ArrayList<>();
        for (Model model : models) {
            result.add(syncOne(modelClass, entityClass, vendorId, model, userId));
            for (Entity entity : allEntities) {
                if (modelEqualEntity(model, entity)) {
                    existsEntites.add(entity);
                    break;
                }
            }
        }
        allEntities.removeAll(existsEntites);
        for (Entity entity : allEntities) {
            remove(entity, userId);
        }
        return result;
    }

}
