package com.yaoyicloud.render;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.util.JsonFormat;
import com.yaoyicloud.message.FxyProtos.PublicRecord;

/**
 * PublicRecord渲染器
 *
 */
public final class PublicRecordRender extends AbstractRender {

    public PublicRecordRender(String cwd) {
        super(cwd);
    }

    /**
     * Docx 渲染
     *
     * @param info 数据
     * @param templateFileContent 模板内容
     * @return 本地文件目录
     * @throws IOException
     */
    public String renderDocx(PublicRecord info, Map<String, Object> addtionalMap, byte[] templateFileContent) throws IOException {
        // TODO: let mapper be package static
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addSerializer(new PublicRecordSerializer(PublicRecord.class));
        mapper.registerModule(module);

        String jsonStr = mapper.writeValueAsString(info);

        // 注： 报告模板的模板变量按照json序列化的结果命名
        // 注： 目前的实现假设：一个session对应一个cwd目录
        ConfigureBuilder builder = Configure.builder();
        builder.bind("dishonestPersons", new LoopRowTableRenderPolicy());
        builder.bind("businessAbnormals", new LoopRowTableRenderPolicy());
        builder.bind("penaltyRecords", new LoopRowTableRenderPolicy());
        builder.bind("taxPenalties", new LoopRowTableRenderPolicy());
        builder.bind("severeViolations", new LoopRowTableRenderPolicy());
        this.docxResultPath =
            this.renderDocx(jsonStr, addtionalMap, templateFileContent, builder,
                Paths.get(cwd, UUID.randomUUID().toString() + ".docx").toString());
        return this.docxResultPath;
    }

    /*
     * 通过序列化和反序列化
     * 1. 进行默认显示规则的数据转换
     * 2. 避免POI-TL处理模板面对复杂数据类型
     */
    public class PublicRecordSerializer extends StdSerializer<PublicRecord> {

        public PublicRecordSerializer() {
            this(null);
        }

        public PublicRecordSerializer(Class<PublicRecord> t) {
            super(t);
        }

        /**
         * 为了增加*Count的数值，定制了序列化方法。 TODO: 可能更简单的方法是使用POI-TL的Spring表达式能力
         */
        @Override
        public void serialize(PublicRecord value, JsonGenerator jgen, SerializerProvider provider)
            throws IOException, JsonProcessingException {

            jgen.writeStartObject();

            jgen.writeArrayFieldStart("dishonestPersons");
            writeRawArray(
                value.getDishonestPersonsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
                jgen);
            jgen.writeEndArray();
            jgen.writeNumberField("dishonestPersonsCount", value.getDishonestPersonsCount());

            jgen.writeArrayFieldStart("businessAbnormals");
            writeRawArray(
                value.getBusinessAbnormalsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
                jgen);
            jgen.writeEndArray();
            jgen.writeNumberField("businessAbnormalsCount", value.getBusinessAbnormalsCount());

            jgen.writeArrayFieldStart("penaltyRecords");
            writeRawArray(
                value.getPenaltyRecordsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
                jgen);
            jgen.writeEndArray();
            jgen.writeNumberField("penaltyRecordsCount", value.getPenaltyRecordsCount());

            jgen.writeArrayFieldStart("taxPenalties");
            writeRawArray(
                value.getTaxPenaltiesList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()), jgen);
            jgen.writeEndArray();
            jgen.writeNumberField("taxPenaltiesCount", value.getTaxPenaltiesCount());

            jgen.writeArrayFieldStart("severeViolations");
            writeRawArray(
                value.getSevereViolationsList().stream().map(o -> (MessageOrBuilder) o).collect(Collectors.toList()),
                jgen);
            jgen.writeEndArray();
            jgen.writeNumberField("severeViolationsCount", value.getSevereViolationsCount());

            jgen.writeRaw(", \"publicRecordSummary\": " + JsonFormat.printer().print(value.getPublicRecordSummary()));

            jgen.writeEndObject();
        }

        private void writeRawArray(List<MessageOrBuilder> values, JsonGenerator jgen)
            throws IOException, InvalidProtocolBufferException {
            String comma = null;
            for (MessageOrBuilder item : values) {
                if (comma != null) {
                    jgen.writeRaw(comma);
                } else {
                    comma = ",";
                }
                jgen.writeRaw(JsonFormat.printer().print(item));
            }
        }
    }
}
