package com.mortals.xhx.module.doc.baseinfo.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.plugin.table.MultipleRowTableRenderPolicy;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.framework.service.impl.AbstractCRUDServiceImpl;
import com.mortals.framework.util.StringUtils;
import com.mortals.xhx.base.system.upload.service.UploadService;
import com.mortals.xhx.common.utils.ExportDocUtil;
import com.mortals.xhx.common.utils.WordUtil;
import com.mortals.xhx.module.doc.baseinfo.dao.DocBaseinfoDao;
import com.mortals.xhx.module.doc.baseinfo.model.DocBaseinfoEntity;
import com.mortals.xhx.module.doc.baseinfo.model.DocBaseinfoQuery;
import com.mortals.xhx.module.doc.baseinfo.service.DocBaseinfoService;
import com.mortals.xhx.module.doc.form.model.DocFormEntity;
import com.mortals.xhx.module.doc.form.model.vo.DocFormVo;
import com.mortals.xhx.module.doc.template.model.DocTemplateEntity;
import com.mortals.xhx.module.doc.template.model.DocTemplateQuery;
import com.mortals.xhx.module.doc.template.service.DocTemplateService;
import com.mortals.xhx.module.platform.model.PlatformEntity;
import com.mortals.xhx.module.platform.model.PlatformQuery;
import com.mortals.xhx.module.platform.service.PlatformService;
import freemarker.template.Template;
import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * DocBaseinfoService
 * doc基础信息 service实现
 *
 * @author zxfei
 * @date 2021-10-16
 */
@Service("docBaseinfoService")
public class DocBaseinfoServiceImpl extends AbstractCRUDServiceImpl<DocBaseinfoDao, DocBaseinfoEntity, Long> implements DocBaseinfoService {
    @Autowired
    private DocTemplateService docTemplateService;
    @Autowired
    private DocBaseinfoService docBaseinfoService;

    @Value("${upload.path}")
    private String filePath;
    @Autowired
    private UploadService uploadService;
    @Autowired
    private PlatformService platformService;

    @Override
    protected void saveBefore(DocBaseinfoEntity entity, Context context) throws AppException {
        //生成样表预览图片
        String samplePath = filePath + entity.getSamplePath();

        String prePath = "preview/";
        String rootPath = this.filePath.endsWith("/") ? this.filePath : this.filePath + "/";
        String filePath = rootPath + (StringUtils.isEmpty(prePath) ? "" : prePath + "/");
        File pathDir = new File(filePath);
        if (!pathDir.exists()) {
            pathDir.mkdirs();
        }

        String newName = RandomUtil.randomNumbers(12) + ".jpg";
        String filePathAll = filePath + newName;
        WordUtil.convertWordToJPEG(samplePath, filePathAll);

        entity.setPreViewPath(prePath + newName);
        //校验模板变量正确性 todo
        if (!ObjectUtils.isEmpty(entity.getTemplatePath())) {

        }
        super.saveBefore(entity, context);
    }

    @Override
    protected void saveAfter(DocBaseinfoEntity entity, Context context) throws AppException {
        if (!ObjectUtils.isEmpty(entity.getDocTemplateEntity())) {
            DocTemplateEntity subEntity = entity.getDocTemplateEntity();
            subEntity.setName(entity.getName() + "-模板");
            subEntity.setDocId(entity.getId());
            subEntity.setCreateUser(context.getUser().getLoginName());
            subEntity.setCreateUserId(context.getUser().getId());
            subEntity.setCreateTime(new Date());
            docTemplateService.save(subEntity, context);
            //解析模板变量
            //docTemplateService.parseDocXml(subEntity, context);
            //TODO
            docTemplateService.parseDocxToJson(subEntity,context);
        }
        super.saveAfter(entity, context);
    }


    @Override
    protected void updateBefore(DocBaseinfoEntity entity, Context context) throws AppException {
        //生成样表预览图片
        String samplePath = filePath + entity.getSamplePath();
        String prePath = "preview/";
        String rootPath = this.filePath.endsWith("/") ? this.filePath : this.filePath + "/";
        String filePath = rootPath + prePath;
        String newName = RandomUtil.randomNumbers(12) + ".jpg";
        String filePathAll = filePath + newName;

        //更新，如果地址变化才重新生成预览图片
        DocBaseinfoEntity sourceEntity = this.get(entity.getId());
        if (!sourceEntity.getSamplePath().equals(entity.getSamplePath())) {
            WordUtil.convertWordToJPEG(samplePath, filePathAll);
            entity.setPreViewPath(prePath + newName);
        }

        if (!sourceEntity.getDocTemplateEntity().getTemplatePath().equals(entity.getDocTemplateEntity().getTemplatePath())) {
          //  docTemplateService.parseDocXml(entity.getDocTemplateEntity(), context);
        }

        super.updateBefore(entity, context);
    }

    @Override
    protected void updateAfter(DocBaseinfoEntity entity, Context context) throws AppException {
        if (!ObjectUtils.isEmpty(entity.getDocTemplateEntity())) {
            DocTemplateEntity subEntity = entity.getDocTemplateEntity();
            subEntity.setUpdateUser(context.getUser().getLoginName());
            subEntity.setUpdateUserId(context.getUser().getId());
            subEntity.setUpdateTime(new Date());
            docTemplateService.update(subEntity, context);
        }
        super.updateAfter(entity, context);
    }

    @Override
    protected void validData(DocBaseinfoEntity entity, Context context) throws AppException {
        //校验数据，平台与名称不能重复
        if (ObjectUtils.isEmpty(entity.getId())) {
            DocBaseinfoEntity docBaseinfoEntity = this.selectOne(new DocBaseinfoQuery().platformSn(entity.getPlatformSn()).name(entity.getName()));
            if (!ObjectUtils.isEmpty(docBaseinfoEntity)) {
                throw new AppException("当前所属平台业务名称已存在！");
            }
        } else {
            DocBaseinfoEntity docBaseinfoEntity = this.get(entity.getId());
            if (!docBaseinfoEntity.getName().equals(entity.getName())) {
                DocBaseinfoEntity docEntity = this.selectOne(new DocBaseinfoQuery().platformSn(entity.getPlatformSn()).name(entity.getName()));
                if (!ObjectUtils.isEmpty(docEntity)) {
                    throw new AppException("当前所属平台业务名称已存在！");
                }
            }
        }

        super.validData(entity, context);
    }

    @Override
    protected void removeAfter(Long[] ids, Context context, int result) throws AppException {
        for (int i = 0; i < ids.length; i++) {
            Long[] templateIds = docTemplateService.find(new DocTemplateQuery().docId(ids[i]), context).stream().map(DocTemplateEntity::getId).toArray(Long[]::new);
            docTemplateService.remove(templateIds, context);
        }
        super.removeAfter(ids, context, result);
    }

    @Override
    public String mergeFormToDocByTemplate(String form, Long templateId, Context context) {
        //转换表单参数为map集合
        ObjectMapper mapper = new ObjectMapper();
        try {
            Map<String, Object> data = mapper.readValue(form, Map.class);
            //遍历查看是否有图片数据，多选框
            data.entrySet().stream().forEach(entry -> {
                if (entry.getKey().indexOf("image") != -1) {
                    //获取值 读取本地图片
                    String imagepath = uploadService.getFilePath(entry.getValue().toString());
                    log.info("Image path: " + imagepath);
                    BufferedImage image = ImgUtil.read(imagepath);
                    String ext = FileUtil.getSuffix(imagepath);
                    String imageStr = ImgUtil.toBase64(image, ext);
                    entry.setValue(imageStr);
                }

                if (entry.getKey().indexOf("ck_") != -1 && !entry.getKey().endsWith("_label")) {
                    String ckStr = MapUtil.getStr(data, entry.getKey() + "_label", "");
                    //获取所有选项
                    List<String> checkboxs = StrUtil.splitTrim(ckStr, "-", -1);
                    //选中的项
                    List<String> ckList = Convert.toList(String.class, entry.getValue());
                    //合并
                    String ckStrs = checkboxs.stream().map(item -> {
                        for (String checked : ckList) {
                            if (checked.equals(item)) {
                                Map<Boolean, String> map = new HashMap<>();
                                map.put(true, item);
                                return map;
                            }
                        }
                        Map<Boolean, String> map = new HashMap<>();
                        map.put(false, item);
                        return map;
                    }).map(m -> m.entrySet().stream().map(m1 -> ExportDocUtil.createCheckBoxStr(m1.getKey(), m1.getValue())).findFirst().orElseGet(() -> "")
                    ).collect(Collectors.joining(""));
                    entry.setValue(ckStrs);
                }
            });
            //查询是否有多选框，
            //获取模板文件地址
            DocTemplateEntity docTemplateEntity = docTemplateService.get(templateId);
            if (!ObjectUtils.isEmpty(docTemplateEntity)) {
                //初始化freeMarkers
                String path = filePath + docTemplateEntity.getTemplatePath();
                int index = StrUtil.lastIndexOfIgnoreCase(path, "/");
                String templatePath = path.substring(0, index);
                //FreeMarkerUtils.initFreeMarkerPath(templatePath);
                String templateName = FileUtil.getName(path);
                //Template template = FreeMarkerUtils.getTemplate(templateName);
                try {
                    // 渲染模板
                    StringWriter sw = new StringWriter();
                  //  template.process(data, sw);
                    MultipartFile multipartFile = new MockMultipartFile(templateName, templateName,
                            ContentType.APPLICATION_OCTET_STREAM.toString(), sw.toString().getBytes(Charset.forName("UTF-8")));
                    String mergedocPath = uploadService.saveFileUpload(multipartFile, "/mergedoc", context.getUser());
                    log.info("mergedocPath:" + mergedocPath);
                    String mergedoc = this.filePath + mergedocPath;
                    //转换预览图片
                    String fileName = RandomUtil.randomNumbers(12) + ".jpg";
                    String preView = this.filePath + "/preview/" + fileName;
                    WordUtil.convertWordToJPEG(mergedoc, preView);
                    log.info("preView:" + mergedocPath);

                    //下载地址拼装
                    String returnStr = mergedocPath + ";" + "/preview/" + fileName;
                    return returnStr;
                } catch (Exception e) {
                    log.error("异常", e);
                }
            }
        } catch (JsonProcessingException e) {
            log.error("转换异常", e);
            throw new AppException("表单参数转换异常:" + e.getMessage());
        }
        return "";
    }



    @Override
    public String submitOtherSystem(String form, Long templateId, String previewPath, String mergeDocPath, Context context) {

        String redirectPath = "";
        DocTemplateEntity docTemplateEntity = docTemplateService.get(templateId);
        if (!ObjectUtils.isEmpty(docTemplateEntity)) {
            //获取平台 提交表单
            DocBaseinfoEntity baseinfoEntity = docBaseinfoService.get(docTemplateEntity.getDocId());
            if (!ObjectUtils.isEmpty(baseinfoEntity)) {
                //对外提交参数， 目前未做异步，重发机制
                PlatformEntity platformEntity = platformService.selectOne(new PlatformQuery().platformSn(baseinfoEntity.getPlatformSn()));
                String url = platformEntity.getCallbackUrl();
                //预览图片与合成模板地址 表单数据
                Map<String, String> data = new HashMap<>();
                data.put("mergeDocPath", mergeDocPath);
                data.put("previewPath", previewPath);
                data.put("form", form);
                String responseBody = HttpUtil.post(url, JSON.toJSONString(data));
                log.info("responseBody:" + responseBody);
                redirectPath = platformEntity.getRedirectUrl();
            }
        }
        return redirectPath;
    }


    @Override
    public String mergeFormToDoc(DocFormEntity docFormVo, Context context) {
        //转换表单参数为map集合
        ObjectMapper mapper = new ObjectMapper();
        ConfigureBuilder builder = Configure.builder();
        try {
            Map<String, Object> data = mapper.readValue(docFormVo.getFormContent(), Map.class);
            //遍历查看是否有图片数据，多选框
            data.entrySet().stream().forEach(entry -> {
                if (entry.getKey().indexOf("image") != -1) {
                    //获取值 读取本地图片
                    String imagepath = uploadService.getFilePath(entry.getValue().toString());
                    log.info("Image path: " + imagepath);
                    BufferedImage image = ImgUtil.read(imagepath);
                    String ext = FileUtil.getSuffix(imagepath);
                    String imageStr = ImgUtil.toBase64(image, ext);
                    entry.setValue(imageStr);
                }
                //构建填充复选框值
                if (entry.getKey().indexOf("ck_") != -1 && entry.getKey().indexOf("v") != -1) {
                    //获取复选框选项，并渲染值
                    String ckStr = StringUtils.substringBetween(entry.getKey(), "v", "v");
                    //获取所有选项
                    List<String> checkboxs = StrUtil.splitTrim(ckStr, "_", -1);
                    //选中的项
                    List<String> ckList = Convert.toList(String.class, entry.getValue());
                    //合并
                    String ckStrs = checkboxs.stream().map(item -> {
                        for (String checked : ckList) {
                            if (checked.equals(item)) {
                                Map<Boolean, String> map = new HashMap<>();
                                map.put(true, item);
                                return map;
                            }
                        }
                        Map<Boolean, String> map = new HashMap<>();
                        map.put(false, item);
                        return map;
                    }).map(m -> m.entrySet().stream().map(m1 -> ExportDocUtil.createCheckBoxStrOther(m1.getKey(), m1.getValue())).findFirst().orElseGet(() -> "")
                    ).collect(Collectors.joining(""));
                    entry.setValue(ckStrs);
                }

                //TODO 单选

                //绑定动态表单
                if (entry.getKey().indexOf("dt_") != -1 ) {
                    builder.bind(entry.getKey(), new MultipleRowTableRenderPolicy());
                }

            });
            //查询是否有多选框，
            //获取模板文件地址
            DocTemplateEntity docTemplateEntity = docTemplateService.get(docFormVo.getTemplateId());
            if (!ObjectUtils.isEmpty(docTemplateEntity)) {

                String path = filePath + docTemplateEntity.getTemplatePath();
                int index = StrUtil.lastIndexOfIgnoreCase(path, "/");
                String templatePath = path.substring(0, index);
                //FreeMarkerUtils.initFreeMarkerPath(templatePath);
                String templateName = FileUtil.getName(path);

                Configure config = builder.build();
                XWPFTemplate template = null;
                ByteArrayOutputStream byteArrayOutputStream = null;
                try {
                   // ClassPathResource classPathResource = new ClassPathResource(path);
                    template = XWPFTemplate.compile(path, config).render(data);
                    byteArrayOutputStream = new ByteArrayOutputStream();
                    template.write(byteArrayOutputStream);

                    MultipartFile multipartFile = new MockMultipartFile(templateName, templateName,
                            ContentType.APPLICATION_OCTET_STREAM.toString(),byteArrayOutputStream.toByteArray());
                    String mergedocPath = uploadService.saveFileUpload(multipartFile, "/mergedoc", context.getUser());
                    log.info("mergedocPath:" + mergedocPath);
                    String mergedoc = this.filePath + mergedocPath;
                    //转换预览图片
                    String fileName = RandomUtil.randomNumbers(12) + ".jpg";
                    String preView = this.filePath + "/preview/" + fileName;
                    WordUtil.convertWordToJPEG(mergedoc, preView);
                    log.info("preView:" + mergedocPath);

                    //下载地址拼装
                    String returnStr = mergedocPath + ";" + "/preview/" + fileName;
                    return returnStr;
                } catch (Exception e) {
                    log.error("渲染模板失败：", e);
                  //  return new byte[0];
                } finally {
                    try {
                        template.close();
                        byteArrayOutputStream.close();
                    } catch (IOException e) {
                        log.error("ioEx：", e);
                    }
                }

            }
        } catch (JsonProcessingException e) {
            log.error("转换异常", e);
            throw new AppException("表单参数转换异常:" + e.getMessage());
        }
        return "";
    }


    public static void main(String[] args) {

        String temp = "/ddd/bbb.jpg";

        System.out.println(temp);

        //UrlPath


    }
}