package com.brilliance.isc.doc.handle.impl.common;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import com.brilliance.isc.common.exception.CommonServiceException;
import com.brilliance.isc.common.trndoc.vo.DoceotVo;
import com.brilliance.isc.doc.constant.DocConstant;
import com.brilliance.isc.doc.handle.ITextProvider;
import com.brilliance.isc.doc.utils.TemplateFactory;
import com.brilliance.isc.common.doc.TextResultVo;
import com.brilliance.isc.utils.ObjectUtils;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import freemarker.template.Template;
import lombok.Builder;
import sun.misc.BASE64Encoder;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 通用面函处理提供者
 * 一般简单的面函处理，不用每个都写Provider，直接new构建此Provider
 * 面函会通过freemarker渲染生成
 */
@Builder
public class SimpleTextProvider implements ITextProvider<Object> {

    private static Logger logger = LoggerFactory.getLogger(SimpleTextProvider.class);
    private static final String FONT = "simhei.ttf";
    private static final String LOGO_PATH = "file://"+Thread.currentThread().getContextClassLoader().getResource("templates/logo.png").getPath();

    /**
     * 模板名称
     */
    private String templateName;

    /**
     * 面函名称
     */
    private String docName;

    /**
     * 支持的Cortypes类型
     */
    private List<String> enableCortypes;

    /**
     * 只返回HTML内容，为套打准备
     */
    private boolean onlyHtml;

    private static Field _fontFamilies;

    private static Map fontFamilies;

    private static void loadFonts(){
        ITextRenderer render = new ITextRenderer();
        ITextFontResolver fontResolver = render.getFontResolver();
        try {
            fontResolver.addFont(FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            fontResolver.addFont("simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            fontResolver.addFont("simkai.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            fontResolver.addFont("times.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            fontResolver.addFont("simfang.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            fontResolver.addFont("msyh.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            fontResolver.addFont("msyhbd.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            fontResolver.addFont("msyhl.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            fontResolver.addFont("arial.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            _fontFamilies = fontResolver.getClass().getDeclaredField("_fontFamilies");
            _fontFamilies.setAccessible(true);
            fontFamilies = (Map)_fontFamilies.get(fontResolver);
        }catch (Exception e){
            logger.error("无法加载字体:{}",e);
        }
    }

    public static void setFontFamily(ITextFontResolver fontResolver){
        try {
            _fontFamilies.set(fontResolver,fontFamilies);
        } catch (Exception e) {
            logger.error("设置字体异常:{}",e);
        }
    }

    static {
        loadFonts();
    }
    /**
     * 当前提供的面函模板名称
     *
     * @return
     */
    @Override
    public String getDocName() {
        return docName;
    }



    /**
     * 输出报文结果
     *
     * @param dataBo   数据
     * @param doceotVo 单条面函信息
     * @param extraData  附加额外的数据，会用putAll的方式放入到rootMap中
     * @return
     */
    @Override
    public TextResultVo outputMessage(Object dataBo, DoceotVo doceotVo,Map<String,Object> extraData) {
        TextResultVo textResultVo = new TextResultVo();
        textResultVo.setFormat(DocConstant.PDF);
        textResultVo.setExtension("pdf");
        //数据拉直转为Map
        Map<String,Object> rootMap = ObjectUtils.dataToMap(dataBo);
        Map<String,String> imgMap = new HashMap<>();
        if(extraData != null) {
            AtomicInteger cnt= new AtomicInteger(0);
            if(!onlyHtml) {
                extraData.entrySet().forEach(entry -> {
                    if (entry.getValue() instanceof String && ((String) entry.getValue()).startsWith("data:image/")) {
                        String cntStr = String.valueOf(cnt.incrementAndGet());
                        imgMap.put(cntStr, (String) entry.getValue());
                        entry.setValue("data:image/" + cntStr);
                    }
                });
            }
            rootMap.putAll(extraData);
        }
        //依旧保留Bo数据
        rootMap.put(DocConstant.TRANS,dataBo);
        rootMap.put(DocConstant.DOCEOT,doceotVo);
        rootMap.put("DOC_NAME",this.getDocName());
        //读取模板
        try (
                Writer osw = new StringWriter();
                ByteArrayOutputStream bos2OfPdf = new ByteArrayOutputStream();
        ){
            Template template = TemplateFactory.getTemplate(templateName,doceotVo.getDocuil());
            //渲染数据
            template.process(rootMap,osw);
            osw.flush();
            String html = osw.toString();
            if(onlyHtml){
                textResultVo.setFormat(DocConstant.HTML);
                textResultVo.setExtension("html");
                html = new BASE64Encoder().encode(html.getBytes("utf-8"));
                textResultVo.setData(html);
                return textResultVo;
            }
            //将html 内容bos转为PDF
            ITextRenderer render = new ITextRenderer();
            ITextFontResolver fontResolver = render.getFontResolver();
            setFontFamily(fontResolver);
            // 解析html生成pdf
            //解决图片相对路径的问题
//            render.getSharedContext().setBaseURL(LOGO_PATH);
            render.getSharedContext().setUserAgentCallback(new SimpleTextUserAgentCallback(render.getOutputDevice()));
            render.getSharedContext().setReplacedElementFactory(new Base64ImgReplacedElementFactory(imgMap));
            html = html.replaceAll("font-family:\\s*黑体","font-family: SimHei");
            html = html.replaceAll("font-family:\\s*宋体","font-family: SimSun");
            html = html.replaceAll("font-family:\\s*仿宋","font-family: FangSong");
            html = html.replaceAll("font-family:\\s*楷体","font-family: KaiTi_GB2312");
            html = html.replaceAll("font-family:\\s*标楷体","font-family: KaiTi_GB2312");
            html = html.replaceAll("font-family:\\s*新罗马体","font-family: Times New Roman");
            html = html.replaceAll("font-family:\\s*微软雅黑","font-family: Microsoft YaHei");
            html = html.replaceAll("<br\\s*>","<br/>").replaceAll("<(/)?\\s*pre\\s*>","<$1p>");
            //替换单独的&前，不能影响其他转义符号,可能大于小于等等也需要
            html = html.replaceAll("&(?!((quot|amp|lt|gt|nbsp|ensp|#12288|#32|emsp|#8197|#8194);))", "&amp;");
            if (html.contains("Times New Roman")){
                html = html.replaceAll("第(.*?)页，共(.*?)页","PAGE $1 OF $2");
            }else{
                if (null != doceotVo.getPandsc() && "Guarantee Issue,Guarantee Amendment,保函开立备查表,保函修改备查表,保函结清通知单".contains(doceotVo.getPandsc())) {
                    html = ObjectUtils.setHtmlEnglishAndNumberFont(html, null);
                }
            }
            html = ObjectUtils.setHtmlNonBreak(html,null);
            //包含千分位的数字处理
            //html = html.replaceAll("\\d+(,\\d{3})+\\.?\\d*", "<span style=\"word-warp: break-word;\">$0</span>");
            //处理通过拷贝的没有千分位的数字文本
            //html = html.replaceAll("(?<=(AUD|CAD|CHF|CNY|DKK|EUR|FIM|FRF|GBP|HKD|JPY|KRW|MOP|NOK|NZD|SEK|SGD|THB|TWD|USD))\\d+\\.?\\d*", "<span style=\"word-warp: break-word;\">$0</span>");
            //更新源文本，方便接口更新
            textResultVo.setSourceContent(html.getBytes("utf-8"));
            textResultVo.setSourceExtension("html");
            render.setDocumentFromString(html);
            render.layout();
            render.createPDF(bos2OfPdf);
            textResultVo.setBinary(bos2OfPdf.toByteArray());
        }catch (Exception e){
            logger.error("Pdf生成异常：{}",e);
            throw  new CommonServiceException("Pdf生成异常");
        }
        return textResultVo;
    }



}
