package cn.wise.sc.energy.power.plant.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.wise.sc.energy.power.plant.business.domain.AbstractEntity;
import cn.wise.sc.energy.power.plant.business.domain.vo.EntityVo;
import cn.wise.sc.energy.power.plant.business.service.IBaseService;
import cn.wise.sc.energy.power.plant.common.core.bean.EntityQuery;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.JpaRepository;

import javax.persistence.Entity;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * @description: 基础服务实现
 * @author: qh
 * @create: 2020-07-14 17:01
 **/
@Slf4j
public class BaseServiceImpl<ID, T extends AbstractEntity<ID>>
        implements IBaseService<ID, T> {

    @Autowired
    JpaRepository<T, ID> repository;

    @Override
    public AbstractEntity<ID> getByID(ID id) {
        Optional<T> optional = repository.findById(id);
        if (optional.isPresent()) {
            return optional.get();
        } else {
            log.warn("没有找到符合主键的实体对象.");
            return null;
        }
    }

    @Override
    public void delByID(ID id) {
        repository.deleteById(id);
    }

    @Override
    public EntityVo add(EntityQuery<T> entityQuery) {
        //获取当前类泛型的参数
        Class<?> tClass = getGenericsClass();
        T t;
        try {
            //实例化  将参数复制  save()
            t = (T) tClass.newInstance();
            BeanUtil.copyProperties(entityQuery, t);
            t = repository.save(t);
            t.toVo();
            return t.toVo();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
            log.error("cn.wise.sc.energy.power.plant.business.service2.impl.BaseServiceImpl.add ===== 反射获取泛型失败!");
        } catch (NullPointerException e) {
            log.error("cn.wise.sc.energy.power.plant.business.service2.impl.BaseServiceImpl.add ===== 反射获取泛型失败!jpa实体需加上@Entitiy");
        }
        return null;
    }

    @Override
    public EntityVo update(EntityQuery<T> entityQuery) {
        //获取当前类泛型的参数
        Class<?> tClass = getGenericsClass();
        T t;
        try {
            //实例化  将参数复制  save()
            t = (T) tClass.newInstance();
            BeanUtil.copyProperties(entityQuery, t);
            Optional<T> optional = repository.findById(Objects.requireNonNull(t.getId()));
            T original = (T) tClass.newInstance();
            if (optional.isPresent()) {
                original = optional.get();
            }
            BeanUtil.copyProperties(original, t);
            t = repository.save(original);
            t.toVo();
            return t.toVo();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
            log.error("cn.wise.sc.energy.power.plant.business.service2.impl.BaseServiceImpl.add ===== 反射获取泛型失败!");
        } catch (NullPointerException e) {
            log.error("cn.wise.sc.energy.power.plant.business.service2.impl.BaseServiceImpl.add ===== 反射获取泛型失败!jpa实体需加上@Entitiy");
        }
        return null;
    }

    @Override
    public List<EntityVo> list() {
        List<T> all = repository.findAll();
        List<EntityVo> rts = new ArrayList<>(all.size());
        for (T t : all) {
            EntityVo entityVo = t.toVo();
            rts.add(entityVo);
        }
        return rts;
    }

    /**
     * 获取父类加载器
     *
     * @return Class
     */
    private Class<?> getGenericsClass() {
        //获取当前类泛型的参数
        ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        Class<?> tClass = null;
        //找到AbstractEntity的实现
        for (Type targetType : actualTypeArguments) {
            Class<?> targetTypeClazz = (Class<?>) targetType;
            if (targetTypeClazz.isAnnotationPresent(Entity.class)) {
                tClass = targetTypeClazz;
            }
        }
        return tClass;
    }
}
