package com.persagy.dmp.rwd.parser.service.impl;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.persagy.dmp.rwd.basic.constant.DigitalDataCategory;
import com.persagy.dmp.rwd.parser.entity.ParserResult;
import com.persagy.dmp.common.exception.BusinessException;
import com.persagy.dmp.common.helper.SpringHelper;
import com.persagy.dmp.common.model.data.RegionValue;
import com.persagy.dmp.define.entity.ObjectInfoDefine;
import com.persagy.dmp.rwd.parser.entity.RegionVO;
import com.persagy.dmp.rwd.parser.service.IInfoDataParser;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 信息点 抽象处理器
 * @author Charlie Yu
 * @date 2021-07-12
 */
@Slf4j
public abstract class AbstractInfoDataParser implements IInfoDataParser {

    private static ObjectMapper objectMapper;

    /**
     * 接口实现
     * @param infoDefine 信息点 定义信息
     * @param valueInfo 信息点 值信息
     * @return
     */
    @Override
    public ParserResult parse(ObjectInfoDefine infoDefine, JsonNode valueInfo) {
        ParserResult result = new ParserResult(infoDefine, valueInfo);
        try {
            // 校验信息点定义
            validateDefine(result);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(StrUtil.format("信息点[{}]定义有误，数据源格式有误！", result.getInfoDefine().getCode()));
        }
        // 空值、非静态信息点不需要值校验
        if(valueInfo == null ||
                JsonNodeType.NULL == valueInfo.getNodeType() ||
                ! DigitalDataCategory.STATIC.getIndex().equalsIgnoreCase(infoDefine.getCategory())) {
            return result;
        }
        try {
            // 值校验
            validateValue(result);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(StrUtil.format("信息点[{}]数据格式有误！", result.getInfoDefine().getCode()));
        }
        return result;
    }

    /**
     * 信息点定义校验
     * @param result 校验参数
     * @throws IOException json转换异常
     */
    protected abstract void validateDefine(ParserResult result) throws IOException;

    /**
     * 信息点值校验
     * @param result 校验参数
     * @throws IOException json转换异常
     */
    protected abstract void validateValue(ParserResult result) throws IOException;

    /**
     * 获取数据
     * @param value
     * @param clazz
     * @param <T>
     * @return
     */
    protected <T> T formatValue(JsonNode value, Class<T> clazz) throws IOException {
        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
            return null;
        }
        return getObjectMapper().readValue(value.toString(), clazz);
    }

    /**
     * 获取数据
     * @param value
     * @param clazz
     * @param <T>
     * @return
     */
    protected <T> List<T> formatListValue(JsonNode value, Class<T> clazz) throws IOException {
        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
            return null;
        }
        JavaType javaType = getObjectMapper().getTypeFactory().constructParametricType(ArrayList.class, clazz);
        return getObjectMapper().readValue(value.toString(), javaType);
    }

    /**
     * 获取数据
     * @param value json
     * @param clazz 泛型类
     * @param <T>
     * @return RegionValue
     */
    protected <T extends Comparable> RegionValue<T> formatRegionValue(JsonNode value, Class<T> clazz) throws IOException {
        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
            return null;
        }
        JavaType javaType = getObjectMapper().getTypeFactory().constructParametricType(RegionVO.class, clazz);
        RegionVO<T> region = getObjectMapper().readValue(value.toString(), javaType);
        return region == null ? null:region.toRegionValue();
    }

    /**
     * 获取数据
     * @param value
     * @param clazz 泛型类
     * @param <T>
     * @return List<RegionValue<T>>
     */
    protected <T extends Comparable> List<RegionValue<T>> formatRegionListValue(JsonNode value, Class<T> clazz) throws IOException {
        if(value == null || JsonNodeType.NULL == value.getNodeType()) {
            return null;
        }
        JavaType javaType = getObjectMapper().getTypeFactory().constructParametricType(RegionVO.class, clazz);
        javaType = getObjectMapper().getTypeFactory().constructParametricType(List.class, javaType);
        List<RegionVO<T>> regionList = getObjectMapper().readValue(value.toString(), javaType);
        return RegionVO.toRegionValueList(regionList);
    }

    /**
     * 获取ObjectMapper
     * @return
     */
    protected ObjectMapper getObjectMapper() {
        if(objectMapper == null) {
            objectMapper = SpringHelper.getBean(ObjectMapper.class);
        }
        return objectMapper;
    }
}
