package com.yaoyicloud.render.platform.update;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.policy.RenderPolicy;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.Descriptors;
import com.google.protobuf.util.JsonFormat;
import com.yaoyicloud.config.CommonDataCache;
import com.yaoyicloud.config.FilerepoProperties;
import com.yaoyicloud.factory.FXYAbstractRender;

import com.yaoyicloud.message.FxyProtos;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;

/**
 * BasicInfo渲染器
 *
 */
@Slf4j
public final class BusinessRender extends FXYAbstractRender {
    private final FilerepoProperties filerepoProperties;
    private final CommonDataCache commonDataCache;

    public BusinessRender(String cwd, FilerepoProperties filerepoProperties, CommonDataCache commonDataCache) {
        super(cwd);
        this.filerepoProperties = filerepoProperties;
        this.commonDataCache = commonDataCache;
    }

    @Override
    protected Map<String, Object> renderDocx(String info, String relationId, Integer counter) throws IOException {
        log.info("开始渲染工商信息报告模块，relationId: {}", relationId);

        // 配置POI-TL渲染器
        // 通过默认protobuf实例来填充不存在的key
        FxyProtos.BasicInfo.Builder basicInfoBuilder = FxyProtos.BasicInfo.newBuilder();
        JsonFormat.parser().merge(info, basicInfoBuilder);

        FxyProtos.BasicInfo defaultInstance = FxyProtos.BasicInfo.getDefaultInstance();
        FxyProtos.BasicInfo mergedProto = defaultInstance.toBuilder()
            .mergeFrom(basicInfoBuilder.build())
            .build();
        if (!mergedProto.hasBasicInfoSummary()) {
            mergedProto = mergedProto.toBuilder()
                    .setBasicInfoSummary(FxyProtos.CheckSummary.getDefaultInstance())
                    .build();
        }
        String completeJson = JsonFormat.printer()
            .includingDefaultValueFields()
            .print(mergedProto);

        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> data = objectMapper.readValue(completeJson, new TypeReference<Map<String, Object>>() {});
        data.replaceAll((k, v) -> v.equals("") ? "-" : v);
        Map<String, Object> newAddtionMap = new HashMap<>();
        Descriptors.Descriptor descriptor = mergedProto.getDescriptorForType();
        for (Descriptors.FieldDescriptor field : descriptor.getFields()) {
            if (field.isRepeated()) {
                List<?> li = (List<?>) mergedProto.getField(field);
                if (li.size() == 0) {
                    newAddtionMap.put(field.getName() + "AltText", "未上传");
                }
            }
        }

        if (newAddtionMap.size() > 0) {
            data.putAll(newAddtionMap);
        }

        Map<String, Object> commonDataCacheData = commonDataCache.getData(relationId);
        if (MapUtils.isNotEmpty(commonDataCacheData)) {
            data.putAll(commonDataCacheData);
        }
        data.put("levelInteger", counter);
        fillBasicDefaultValues(data);
        fillCommonDataCacheData(data, relationId);
        return data;
    }

    @Override
    protected ConfigureBuilder builder(String relationId) {
        ConfigureBuilder builder = Configure.builder();
        RenderPolicy indicatorsRenderPolicy = this.indicatorsRenderPolicy();
        Map<String, Object> commonDataCacheData = commonDataCache.getData(relationId);

        builder.bind("basicInfoChecks", indicatorsRenderPolicy);
        builder.bind("sameaddress",
            this.addDefaultRowForEmptyTable((Boolean) commonDataCacheData.get("same_addr_error_flag")));
        builder.bind("samecontactNumberDatas",
            this.addDefaultRowForEmptyTable((Boolean) commonDataCacheData.get("same_tel_error_flag")));
        builder.bind("sameExecutivesNames",
            this.addDefaultRowForEmptyTable((Boolean) commonDataCacheData.get("same_executives_name_flag")));
        builder.addPlugin('^', this.pictureRenderPolicy());
        builder.useSpringEL();
        return builder;
    }

    @Override
    protected String getBasicPath() throws IOException {
        return filerepoProperties.getBasePath();
    }

    @Override
    protected String getReportImagePath() {
        return filerepoProperties.getReportImagePath();
    }

    /**
     * 填充默认值，确保所有必要字段都存在
     */
    private void fillBasicDefaultValues(Map<String, Object> data) {
        Map<String, Object> basicInfoSummary = (Map<String, Object>) data.get("basicInfoSummary");
        basicInfoSummary.replaceAll((k, v) -> v.equals("") ? "-" : v);
        Map<String, Object> platformExt = (Map<String, Object>) data.get("platformExt");
        platformExt.replaceAll((k, v) -> v.equals("") ? "-" : v);
        Object updateSource = platformExt.get("updateSource");
        if (updateSource.equals("-")) {
            platformExt.put("updateSource", "");
        }

        Object basicInfoCheckResult = data.get("basicInfoCheckResult");
        if (Objects.equals(basicInfoCheckResult, "-")) {
            data.put("basicInfoCheckResult", "0");
        }
        processJsonData(data, "sameaddress");
        processJsonData(data, "samecontactNumberDatas");
        processJsonData(data, "sameExecutivesNames");

        List<Map<String, Object>> sameExecutivesNames = (List<Map<String, Object>>) data.get("sameExecutivesNames");

        if (CollectionUtils.isNotEmpty(sameExecutivesNames)) {
            Map<Object, Long> nameCountMap = sameExecutivesNames.stream()
                .map(item -> item.get("name"))
                .filter(Objects::nonNull)
                .collect(Collectors.groupingBy(name -> name, Collectors.counting()));

            int size = nameCountMap.size();
            data.put("sameNameSize", size);
        }
        data.put("sameNameSize", 0);
    }

    private void fillCommonDataCacheData(Map<String, Object> data, String relationId) {
        Integer index = 1;
        Map<String, Object> secondsMap = new HashMap<>();
        commonDataCache.insertData(relationId, "same_tel_error_flag", false);
        commonDataCache.insertData(relationId, "same_addr_error_flag", false);
        commonDataCache.insertData(relationId, "same_executives_name_flag", false);
        List<Map<String, Object>> basicInfoChecks = (List<Map<String, Object>>) data.get("basicInfoChecks");
        if (CollectionUtils.isEmpty(basicInfoChecks)) {
            index++;
        } else {
            for (Map<String, Object> basicInfoCheck : basicInfoChecks) {
                String category = (String) basicInfoCheck.get("category");
                if (category == null) {
                    continue;
                }
                switch (category) {
                    case "same_addr_error":
                        index++;
                        secondsMap.put("sameaddress", index.toString());
                        commonDataCache.insertData(relationId, "same_addr_error_flag", true);
                        break;
                    case "same_tel_error":
                        index++;
                        secondsMap.put("samecontactNumberDatas", index.toString());
                        commonDataCache.insertData(relationId, "same_tel_error_flag", true);
                        break;
                    case "same_executives_name":
                        index++;
                        secondsMap.put("sameExecutivesNames", index.toString());
                        commonDataCache.insertData(relationId, "same_executives_name_flag", true);
                        break;
                    default:
                        break;
                }
            }
            index++;
        }
        secondsMap.put("moduleTail", index.toString());
        data.put("secondsMap", secondsMap);
    }

}
