package link.at17.mid.tushare.web.controller;

import java.lang.reflect.Method;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import jakarta.validation.UnexpectedTypeException;
import link.at17.mid.tushare.dto.R;
import link.at17.mid.tushare.interfaces.IConfig;
import link.at17.mid.tushare.service.ConfigService;
import link.at17.mid.tushare.web.exception.PageNotFoundException;
import lombok.extern.slf4j.Slf4j;

@Controller
@RequestMapping("/admin/manage/reviews")
@Slf4j
public class ConfigController extends BaseController {

    @Autowired
    Validator validator;
    
    @Autowired
    ConfigService configService;
    
    @GetMapping("/set/system/{configField}.html")
    public String configPage(@PathVariable String configField) {
        if (configField == null || configField.contains(".") || configField.contains("/")) {
            throw new PageNotFoundException();
        }
        return "admin/manage/reviews/set/system/" + configField;
    }
    
    @PostMapping("/set/system/{configField}.html")
    @ResponseBody
    public <T extends IConfig<T>> R<?> saveConfig(@PathVariable String configField, @Validated @RequestBody JsonNode config) throws Exception {
        Class<T> clazz = configService.getConfigClassByField(configField);
        if (clazz == null) {
            throw new PageNotFoundException();
        }
        return R.judgeThrow(() -> {
            T newConfig = (T)new ObjectMapper().treeToValue(config, clazz);
            
            Method method = this.getClass().getMethod("saveConfig", String.class, JsonNode.class);
            MethodParameter methodParameter = new MethodParameter(method, 1);

            // 执行校验
            if (validator.supports(clazz)) {
                try {
                    BindingResult bindingResult = new BeanPropertyBindingResult(newConfig, clazz.getSimpleName());
                    validator.validate(newConfig, bindingResult);
    
                    if (bindingResult.hasErrors()) {
                        throw new MethodArgumentNotValidException(methodParameter, bindingResult);
                    }
                }
                catch (UnexpectedTypeException e) {
                    // 对指定类型未找到 validator，忽略之
                    log.debug("Cannot find a validator for {}", clazz.getName());
                }
            }
            
            T oldConfig = configService.getConfig(clazz);
            oldConfig.mergeFrom(newConfig);
            return oldConfig.saveOrUpdate();
        });
    }

}
