package quant.rich.emoney.controller.common;

import java.lang.reflect.Field;
import java.util.Optional;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.extern.slf4j.Slf4j;
import quant.rich.emoney.exception.RException;
import quant.rich.emoney.pojo.dto.R;

/**
 * 更新实体类中 Boolean 字段的抽象控制器，一般用于实体类中包含 Boolean 字段的前端更新
 * <p>
 * 前端实体类数据列表中，常有 CheckBox 或 Switch 等控件，希望通过点击数据表中的控件直接修改行对象
 * Boolean 值的，可用该方法。需要引入功能的需 extends 本类，如对 {@code Plan} 生效，则可在其控制器
 * {@code PlanController} 中：<p>
 * 
 * <code> PlanController <b>extends</b> UpdateBoolController&lt;Plan></code>
 * @param <T> 实体类型
 * @see #updateBool(String, String, Boolean)
 */
@Slf4j
public abstract class UpdateBoolServiceController<T> extends ServiceController<T> {
    
    protected ObjectMapper mapper = new ObjectMapper();

    /**
     * 更新布尔值主方法，以 form 形式 POST，uri: /updateBool，表单字段名需与该方法参数名一致
     * @param id 欲修改的实体类的实例化对象的主键值
     * @param field 欲修改的实体类的实例化对象的布尔字段名
     * @param value 需要修改为的布尔值
     * @return
     */
    @PostMapping("/updateBool")
    @ResponseBody
    protected 
    R<?> updateBool(String id, String field, Boolean value) {
        

        // 获取表信息
        TableInfo tableInfo = TableInfoHelper.getTableInfo(thisType);
        Object converted = mapper.convertValue(id, tableInfo.getKeyType());
        
        // 获取 Service
        
        try {
            // 获取主键名
            String idField = tableInfo.getKeyColumn();
            // 获取指定布尔字段的字段信息
            Field declaredField = thisType.getDeclaredField(field);
            // 获取指定布尔字段在数据表中的映射字段信息
            Optional<TableFieldInfo> fieldInfo = tableInfo.getFieldList().stream()
                    .filter(f -> f.getProperty().equals(field))
                    .findFirst();
            
            if (fieldInfo.isEmpty()) {
                throw RException.badRequest("无法根据 field: " + field + " 找到类内字段信息");
            }
            
            if (declaredField.getType().equals(Boolean.class)
                || declaredField.getType().equals(boolean.class)    
                ) {
                return R.judge(getThisService().update(
                    new UpdateWrapper<T>()
                        .set(fieldInfo.get().getColumn(), value)
                        .eq(idField, converted)
                        ), "更新失败，请查看日志");
            }
            else {
                throw RException.badRequest("field: " + field + " 不为布尔值类型字段");
            }
        }
        catch (NoSuchFieldException | SecurityException e) {
            throw RException.badRequest("获取字段 " + field + " 错误");
        }
    }

}
