package quant.rich.emoney.controller.common;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import quant.rich.emoney.exception.RException;
import quant.rich.emoney.pojo.dto.LayPageReq;
import quant.rich.emoney.pojo.dto.LayPageResp;
import quant.rich.emoney.pojo.dto.R;

/**
 * 在控制器中提供实体类的 service<p>
 * 
 * 继承后，可直接通过 {@code thisType} 和 {@code thisService} 获取实体类型和对应的服务实例<p>
 * 也获得部分能力，但控制方法及 Mapping 路径要继承后自己写。<p>
 * 可获得的能力：
 * <ul>
 * <li>list
 * <li>getOne
 * <li>delete
 * <ul>
 * 
 * @param <T> 实体类型
 */
@Slf4j
public abstract class ServiceController<T> extends BaseController {
    
    @Autowired
    private ApplicationContext ctx;

    protected IService<?> thisService;
    
    protected Class<?> thisType;

    @PostConstruct
    void init() {
        @SuppressWarnings("rawtypes")
        Map<String, IService> beans = ctx.getBeansOfType(IService.class);
        ResolvableType thisType = ResolvableType.forClass(this.getClass()).as(ServiceController.class);
        @SuppressWarnings("unchecked")
        // 获取本类的实体类
        Class<T> clazz = (Class<T>) thisType.getGeneric(0).resolve();
        this.thisType = clazz;
        for (IService<?> service : beans.values()) {
            ResolvableType type = ResolvableType.forClass(service.getClass()).as(IService.class);
            Class<?> entityType = type.getGeneric(0).resolve();
            if (entityType == clazz) {
                this.thisService = service;
            }
        }
        if (thisService == null) {
            log.error("获取本例实体类服务失败，请检查");
        }
    }
    
    @SuppressWarnings("unchecked")
    protected IService<T> getThisService() {
        return (IService<T>)this.thisService;
    }
    
    /**
     * 返回实例类列表
     * @param pageReq
     * @return
     */
    protected LayPageResp<?> list(LayPageReq<T> pageReq) {
        Page<T> planPage = getThisService().page(pageReq);
        return new LayPageResp<>(planPage);
    }

    /**
     * 根据 id 获取实例化对象。如果 id 为空则返回通过默认无参构造器构造的新实例化对象
     * @param id
     * @return
     */
    protected R<?> getOne(Serializable id) {
        // id 为空，返回一个新实例化对象
        if (id == null) {
            try {
                return R.ok(thisType.getConstructor().newInstance());
            } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException | NoSuchMethodException | SecurityException e) {
                final String s = "根据默认构造器创建新实例化对象失败";
                log.error(s, e);
                throw RException.internalServerError(s);
            }
        }
        
        // 否则从数据库取
        T exist = getThisService().getById(id);
        return R.judge(exist != null, exist, "无法找到对应 ID 的 ProxySetting");
    }
    
    /**
     * 保存
     * @param object
     * @return
     */
    protected R<?> save(T object) {
        return 
            R.judge(
                () -> getThisService().saveOrUpdate(object),
                "新增或保存失败");
    }
    
    /**
     * 删除
     * @param id
     * @return
     */
    protected R<?> delete(Serializable id) {
        return R.judge(getThisService().removeById(id), "删除失败，是否已删除？");
    }

}
