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

import com.brilliance.isc.bo.Bch;
import com.brilliance.isc.common.api.bch.service.BchService;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.doc.ITransactionDocSet;
import com.brilliance.isc.common.doc.TextResultVo;
import com.brilliance.isc.common.transaction.vo.BaseTransactionVo;
import com.brilliance.isc.common.trndoc.service.DoceotService;
import com.brilliance.isc.common.trndoc.vo.DoceotVo;
import com.brilliance.isc.common.util.Utils;
import com.brilliance.isc.constant.ErrorCode;
import com.brilliance.isc.doc.annotation.DocFunc;
import com.brilliance.isc.doc.constant.DocConstant;
import com.brilliance.isc.doc.convert.ResultConvert;
import com.brilliance.isc.doc.handle.ITextProvider;
import com.brilliance.isc.doc.handle.impl.common.MethodProvider;
import com.brilliance.isc.doc.handle.impl.common.SimplePdfFormProvider;
import com.brilliance.isc.doc.handle.impl.common.SimpleTextProvider;
import com.brilliance.isc.exception.SSTFException;
import com.brilliance.isc.utils.ObjectUtils;
import com.brilliance.isc.utils.StringUtils;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

public abstract class AbstractTransactionDocSet<B> implements ITransactionDocSet<B> {

    private static final int UNKNOW_CORTYP_ORDER = 90;
    /**
     * 默认每一个CorTyp顺序
     */
    private static Map<String, Integer> corTypeOrder = new HashMap<>();

    static {
        //默认的CorTyp级别
        corTypeOrder.put("INT", 0);
        corTypeOrder.put("BOL", 0);
        corTypeOrder.put("TSU", 0);
        corTypeOrder.put("DTA", 0);
        corTypeOrder.put("DTE", 0);
        corTypeOrder.put("DTG", 0);
        corTypeOrder.put("TXT", 0);
        corTypeOrder.put("IZV", 0);
        corTypeOrder.put("SPA", 0);
        corTypeOrder.put("ERX", 0);
        corTypeOrder.put("ERC", 0);
        corTypeOrder.put("ELC", 0);
        corTypeOrder.put("FMT", 0);

        corTypeOrder.put("SWT", 1);
        corTypeOrder.put("TLX", 3);
        corTypeOrder.put("LET", 5);
        corTypeOrder.put("FAX", 7);
        corTypeOrder.put("TCO", 7);
        corTypeOrder.put("EML", 9);
    }

    @Autowired
    protected DoceotService doceotService;

    @Autowired
    private BchService bchService;

    @Autowired
    private ResultConvert resultConvert;
    /**
     * 存放所有的面板报文提供者
     */
    private Map<String, ITextProvider> providerMap = new HashMap<>();
    /**
     * 每一个报文面函支持的CORTYP集合
     */
    private Map<String, Set<String>> supportSet = new HashMap<>();

    /**
     * 获取指定DocName支持的
     *
     * @param docName
     * @return 支持的CorType
     */
    public List<String> getCortypByDocName(String docName) {
        Set<String> corTypSet = supportSet.get(docName);
        if (corTypSet == null) {
            return new ArrayList<>();
        }
        return new ArrayList<>(corTypSet);
    }

    /**
     * 支持可以切换的面函报文格式
     * Per Medium
     * LET、SWT、FAX、ELC等
     *
     * @param doceotVo
     * @return
     */
    @Override
    public List<String> getEnableCortypes(DoceotVo doceotVo) {
        return getCortypByDocName(doceotVo.getDocnam());
    }

    public void buildLetterProvider(String transName, String... docNames) {
        for (String docName : docNames) {
            String docNameOfLet = buildDocLetName(docName);
            SimpleTextProvider simpleTextProvider = SimpleTextProvider.builder().docName(docNameOfLet)
                    .templateName(buildDocLetTemplate(transName, docName)).build();
            providerMap.put(simpleTextProvider.getDocName(), simpleTextProvider);
        }
    }

    /**
     * 输入原html，目前主要是套打使用
     * @param transName
     * @param docNames
     */
    public void buildHTMLLetterProvider(String transName, String... docNames) {
        for (String docName : docNames) {
            String docNameOfLet = buildDocLetName(docName);
            SimpleTextProvider simpleTextProvider = SimpleTextProvider.builder().docName(docNameOfLet)
                    .templateName(buildDocLetTemplate(transName, docName)).onlyHtml(true).build();
            providerMap.put(simpleTextProvider.getDocName(), simpleTextProvider);
        }
    }

    public void buildFtlProvider(String transName, String... docNames) {
        for (String docName : docNames) {
            String docNameOfLet = buildDocLetName(docName);
            SimpleTextProvider simpleTextProvider = SimpleTextProvider.builder().docName(docNameOfLet)
                    .templateName(buildFtlLetTemplate(transName, docName)).build();
            providerMap.put(simpleTextProvider.getDocName(), simpleTextProvider);
        }
    }

    public void buildPdfFormLetterProvider(String transName, String... docNames) {
        for (String docName : docNames) {
            String docNameOfLet = buildDocLetName(docName);
            SimplePdfFormProvider simplePdfFormProvider = SimplePdfFormProvider.builder().docName(docNameOfLet)
                    .templateName(buildDocPdfTemplate(transName, docName)).build();
            providerMap.put(simplePdfFormProvider.getDocName(), simplePdfFormProvider);
        }
    }

    /**
     * 加入企业名录面函
     */
    public void addEntmodLetter() {
        String docNameOfLet = buildDocLetName("ENTSUBPEN1");
        SimpleTextProvider simpleTextProvider = SimpleTextProvider.builder().docName(docNameOfLet)
                .templateName(buildDocLetTemplate("COMMON", "ENTSUBPEN1")).build();
        providerMap.put(simpleTextProvider.getDocName(), simpleTextProvider);
    }

    /**
     * 加入委托方代付面函
     */
    public void addDftcreLetter() {
        String docNameOfLet = buildDocLetName("DFTPAY1");
        SimpleTextProvider simpleTextProvider = SimpleTextProvider.builder().docName(docNameOfLet)
                .templateName(buildDocLetTemplate("COMMON", "DFTPAY1")).build();
        providerMap.put(simpleTextProvider.getDocName(), simpleTextProvider);
    }

    /**
     * 加入融资放款面函
     */
    public void addTrtcreLetter() {
        String docNameOfLet = buildDocLetName("TRTAPL1");
        SimpleTextProvider simpleTextProvider = SimpleTextProvider.builder().docName(docNameOfLet)
                .templateName(buildDocLetTemplate("COMMON", "TRTAPL1")).build();
        providerMap.put(simpleTextProvider.getDocName(), simpleTextProvider);
    }

    /**
     * 加入融资还款面函
     */
    public void addBptbckLetter() {
        String docNameOfLet = buildDocLetName("PAYAPL1");
        SimpleTextProvider simpleTextProvider = SimpleTextProvider.builder().docName(docNameOfLet)
                .templateName(buildDocLetTemplate("COMMON", "PAYAPL1")).build();
        providerMap.put(simpleTextProvider.getDocName(), simpleTextProvider);
    }

    /**
     * 加入CIPS面函
     */
    public void addCipsLetter() {
        String docNameOfLet = buildDocLetName("CIPSPAY2");
        SimpleTextProvider simpleTextProvider = SimpleTextProvider.builder().docName(docNameOfLet)
                .templateName(buildDocLetTemplate("COMMON", "CIPSPAY2")).build();
        providerMap.put(simpleTextProvider.getDocName(), simpleTextProvider);
    }
    /**
     * 加入发报交易面函
     */
    public void addXxtfreLetter1() {
        String docNameOfLet = buildDocLetName("XXTFRE1");
        SimpleTextProvider simpleTextProvider = SimpleTextProvider.builder().docName(docNameOfLet)
                .templateName(buildDocLetTemplate("COMMON", "XXTFRE1")).build();
        providerMap.put(simpleTextProvider.getDocName(), simpleTextProvider);
    }
    public void addXxtfreLetter2() {
        String docNameOfLet = buildDocLetName("XXTFRE2");
        SimpleTextProvider simpleTextProvider = SimpleTextProvider.builder().docName(docNameOfLet)
                .templateName(buildDocLetTemplate("COMMON", "XXTFRE2")).build();
        providerMap.put(simpleTextProvider.getDocName(), simpleTextProvider);
    }
    private void loadSettleSessionXXX(B trnBo) {
        loadSettleSession(trnBo);
    }

    /**
     * 请各子类实现好当前交易的loadSettleSession加载
     * 已在controller层加载上下文
     * @param trnBo
     */
    public void loadSettleSession(B trnBo) {

    }


    public String buildDocLetName(String docName) {
        return docName + "_" + DocConstant.COR_TYP_LET;
    }

    public String buildMethodKey(String docName, String cortype) {
        return docName + "_" + cortype;
    }

    public String buildDocLetTemplate(String transName, String docName) {
        return transName.toUpperCase() + "_" + buildDocLetName(docName) + ".html";
    }

    public String buildFtlLetTemplate(String transName, String docName) {
        return transName.toUpperCase() + "_" + buildDocLetName(docName) + ".ftl";
    }

    public String buildDocPdfTemplate(String transName, String docName) {
        return transName.toUpperCase() + "_" + buildDocLetName(docName) + ".pdf";
    }


    public String getUseCortype(DoceotVo doceotVo) {
        return doceotService.getUseCORTYP(doceotVo);
    }


    @Override
    public TextResultVo outputMessage(B trnBo, DoceotVo doceotVo) {
        //加载会话，已做优化，不会反复加载SettleSession
        loadSettleSessionXXX(trnBo);

        String corType = getUseCortype(doceotVo);
        //面函系列都走此分支
        if (DocConstant.COR_TYP_LET.equals(corType)) {
            ITextProvider textProvider = providerMap.get(buildDocLetName(doceotVo.getDocnam()));
            if (textProvider == null) {
                throw new SSTFException(ErrorCode.CONFIG_READ_ERROR, doceotVo.getDocnam() + "-LET:模板未支持");
            }
            Map<String, Object> extraMap = buildExtraMapForLetter(trnBo, doceotVo);
            String trnName = SettleContext.getTransName();
            if("NITOPN".equalsIgnoreCase(trnName)
                    ||"NITPOP".equalsIgnoreCase(trnName)
                    ||"NITAME".equalsIgnoreCase(trnName)
                    ||"NITPAM".equalsIgnoreCase(trnName)
                    ||"HITOPN".equalsIgnoreCase(trnName)
                    ||"HITPOP".equalsIgnoreCase(trnName)
                    ||"HITAME".equalsIgnoreCase(trnName)
                    ||"HITPAM".equalsIgnoreCase(trnName)
            ){
                //String giduil = ObjectUtils.getFieldValue(trnBo, "nidgrp//rec//giduil");
                if(extraMap != null && extraMap.containsKey("gidtxt")){
                    String newgidtxt = ObjectUtils.replaceGidTextSpace((String)extraMap.get("gidtxt"));
                    // 针对于简式修改给与文本样式
                    String plateflg = ObjectUtils.getFieldValue(trnBo,"nitamep//plateflg");
                    if(StringUtils.isNotEmpty(plateflg) && StringUtils.isNotEmpty(newgidtxt)){
                        if(newgidtxt.contains("<p>")){
                            newgidtxt = newgidtxt.replaceAll("<p>","<p style=\"line-height: 1.5;\">");
                        }
                    }
                    extraMap.put("gidtxt",newgidtxt);
                    //中文保函英文大写O特殊处理，以便和零区别开来,启用更宽的Arial字体
                    //if ("cn".equalsIgnoreCase(giduil)) {
                    //    ObjectUtils.distinguishOAndZero(extraMap, "gidtxt");
                    //    ObjectUtils.distinguishOAndZero(extraMap, "bGIDTXT");
                    //}
                }
            }
            TextResultVo textResultVo = textProvider.outputMessage(trnBo, doceotVo, extraMap);
            return textResultVo;
        }

        //报文系列则需要函数一一实现
        //函数添加DocFun注解 面函名称+对应文档类型
        String methodKey = buildMethodKey(doceotVo.getDocnam(), corType);
        ITextProvider textProvider = providerMap.get(methodKey);
        if (textProvider == null) {
            //只是临时返回的，后面要去掉
            TextResultVo textResultVo = new TextResultVo();
            textResultVo.setData(String.format("%s的%s格式报文开发中", doceotVo.getDocnam(), corType));
            textResultVo.setFormat("text");
            textResultVo.setExtension("txt");
            return textResultVo;
            //throw new UnknowDocNameException(doceotVo.getDocnam() +"-"+ corType+":模板未支持");
        }
        TextResultVo textResultVo = textProvider.outputMessage(trnBo, doceotVo, null);
        if (trnBo instanceof BaseTransactionVo) {
            //交易生成的报文格式，需支持格式转换，目前暂支持SWT999的转换 
            textResultVo = resultConvert.convert((BaseTransactionVo) trnBo, doceotVo, textResultVo);
        }
        return textResultVo;
    }



    /**
     * 返回当前组件，每种面函模块支持的CorType
     * 通过扫描成员方法、providerMap实现
     */
    public void scanDocCortypSupport() {
        //获取扫描的临时结果集
        Map<String, List<CorTypeOrderBean>> tempSupoortSet = new HashMap<>();

        providerMap.keySet().forEach(key -> {
            String[] arr = key.toUpperCase().split("_");
            if (arr.length < 2) {
                return;
            }
            String docName = arr[0];
            List<CorTypeOrderBean> cortypList = tempSupoortSet.get(docName);
            if (cortypList == null) {
                cortypList = new ArrayList<>();
                tempSupoortSet.put(docName, cortypList);
            }
            CorTypeOrderBean corTypeOrderBean = CorTypeOrderBean.builder().corType(arr[1]).order(corTypeOrder.get(arr[1])).build();
            cortypList.add(corTypeOrderBean);
        });

        for (Method method : this.getClass().getMethods()) {
            method.setAccessible(true);
            if (!method.isAnnotationPresent(DocFunc.class)) {
                continue;
            }

            DocFunc docFunc = method.getAnnotation(DocFunc.class);
            String docName = docFunc.name().toUpperCase();

            String cortyp = docFunc.cortyp();
            List<CorTypeOrderBean> cortypList = tempSupoortSet.get(docName);
            if (cortypList == null) {
                cortypList = new ArrayList<>();
                tempSupoortSet.put(docName, cortypList);
            }
            int order = docFunc.order();
            if (order < 0) {
                if (corTypeOrder.containsKey(cortyp)) {
                    order = corTypeOrder.get(cortyp);
                } else {
                    //设置一个经验值，表示放到末尾
                    order = UNKNOW_CORTYP_ORDER;
                }
            }
            CorTypeOrderBean corTypeOrderBean = CorTypeOrderBean.builder()
                    .corType(cortyp).order(order).required(docFunc.required()).build();
            cortypList.add(corTypeOrderBean);
            //将方法加入到providerMap
            String methodKey = buildMethodKey(docName, cortyp);
            providerMap.put(methodKey, new MethodProvider(this, method));
        }

        //tempSupoortSet，映射为supportSet
        tempSupoortSet.entrySet().forEach(stringListEntry -> {
            List<String> cortypList = stringListEntry.getValue().stream()
                    .sorted(Comparator.comparingInt(CorTypeOrderBean::getOrder))
                    .map(CorTypeOrderBean::getCorType)
                    .collect(Collectors.toList());
            //将排序后的CorTyp去重并转为LinkedHashSet
            Set<String> corTypSet = new LinkedHashSet<>();
            corTypSet.addAll(cortypList);
            supportSet.put(stringListEntry.getKey(), corTypSet);
        });


    }

    /**
     * 支持子类对letter类型面函提供添加信息，子类可以重写
     *
     * @return
     */
    public Map<String, Object> buildExtraMapForLetter(B trnBo, DoceotVo doceotVo) {
        return new HashMap<>();
    }

    /**
     * 查找发报行BIC
     */
    protected String getSendBic() {
        String bicCode = "";
//        Bch bch = bchMapper.selectByBranch(SettleContext.getUserSession().getWrkbch().getBchkey());
        Bch bch = bchService.getDirectAccBch(SettleContext.getUserSession().getWrkbch().getBranch());

        if (bch != null) {
            bicCode = bch.getSwfcod();
        } else {
            bicCode = SettleContext.getUserSession().getWrkbch().getSwfcod();
        }
        return bicCode;
    }

    /**
     * 根据指定的连接符 连接字符串str1 和 str2
     *
     * @param str1
     * @param str2
     * @param linkCode
     * @return
     */
    protected String linkStr(String str1, String str2, String linkCode) {
        if (StringUtils.isNotEmpty(str1)) {
            if (StringUtils.isEmpty(str2)) {
                return str1;
            } else {
                return str1 + linkCode + str2;
            }
        }
        return "";
    }

    /**
     * 输出MT报文的日期格式 YYMMDD
     *
     * @param date
     * @return
     */
    protected String printSwiftDate(Date date) {
        if (date != null) {
            return Utils.fmtDate(date, "yyMMdd");
        }
        return null;
    }

    public boolean isCortypRequired(String docName, String cortyp) {
        String methodKey = buildMethodKey(docName, cortyp);
        ITextProvider textProvider = providerMap.get(methodKey);
        if (textProvider == null) {
            return false;
        }
        if (!(textProvider instanceof MethodProvider)) {
            return false;
        }

        Method method = ((MethodProvider) textProvider).getMethod();
        if (method.isAnnotationPresent(DocFunc.class)) {
            DocFunc docFunc = method.getAnnotation(DocFunc.class);
            return docFunc.required();
        }
        return false;
    }

    public boolean isSWTRequired(String docName) {
        return isCortypRequired(docName, DocConstant.COR_TYP_SWT);
    }

    /**
     * 用于记录支持的CorType
     */
    @Builder
    @Setter
    @Getter
    public static class CorTypeOrderBean {
        private String corType;
        private int order;
        private boolean required;
    }

}
