package com.zt.plat.module.qms.business.reportdoc.service;

import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zt.plat.framework.common.exception.ServiceException;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.framework.security.core.LoginUser;
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
import com.zt.plat.module.infra.api.businessfile.BusinessFileApi;
import com.zt.plat.module.infra.api.businessfile.dto.BusinessFileSaveReqDTO;
import com.zt.plat.module.infra.api.file.FileApi;
import com.zt.plat.module.infra.api.file.dto.FileCreateReqDTO;
import com.zt.plat.module.infra.api.file.dto.FileRespDTO;
import com.zt.plat.module.qms.business.reportdoc.constant.ReportDocConstant;
import com.zt.plat.module.qms.business.reportdoc.controller.vo.ReportDocumentFileSaveReqVO;
import com.zt.plat.module.qms.business.reportdoc.dal.dataobject.ReportDocumentFileDO;
import com.zt.plat.module.qms.business.reportdoc.dal.dataobject.ReportDocumentMainDO;
import com.zt.plat.module.qms.business.reportdoc.dal.dataobject.ReportDocumentTypeDO;
import com.zt.plat.module.qms.business.reportdoc.listener.ReportDocListenerConstant;
import com.zt.plat.module.qms.common.data.dal.dataobject.DataTemplateDO;
import com.zt.plat.module.qms.common.data.service.DataTemplateService;
import com.zt.plat.module.qms.common.dic.controller.vo.DictionaryBusinessRespVO;
import com.zt.plat.module.qms.common.dic.service.DictionaryBusinessService;
import com.zt.plat.module.system.api.iwork.IWorkIntegrationApi;
import com.zt.plat.module.system.api.iwork.dto.IWorkGenericWorkflowCreateReqDTO;
import com.zt.plat.module.system.api.iwork.dto.IWorkOperationRespDTO;
import com.zt.plat.module.system.api.iwork.dto.IWorkWorkflowCreateReqDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

import static com.zt.plat.module.qms.enums.ErrorCodeConstants.REPORT_DOCUMENT_FILE_NOT_EXISTS;

/*
* 处理报告附件和发起iwork流程
* */
@Service("reportDocumentAssistService")
@Slf4j
public class ReportDocumentAssistService {
    @Resource
    private IWorkIntegrationApi iWorkIntegrationApi;

    @Value("${zzjc.html2pdf.addr:}")
    private String html2pdfAddr;

    @Resource private ReportDocumentDataService reportDocumentDataService;
    @Resource private ReportDocumentTypeService reportDocumentTypeService;
    @Resource private ReportDocumentFileService reportDocumentFileService;
    @Resource private DataTemplateService dataTemplateService;
    @Resource private FileApi fileApi;
    @Resource private BusinessFileApi businessFileApi;
    @Resource private DictionaryBusinessService dictionaryBusinessService;

    private final String iwork_sjly = "dt_dsc";   //

//    private String sequenceKey = "QMS_REPORT_IWORK_CODE";

    // todo 判断是否更新pdf
    public boolean checkUpdateDocFile(JSONObject variables){
        return true;
    }

    /*
     * 更新报告附件，并发起iwork流程*/
    public void updateDocFileAndCreateIWorkflow(JSONObject variables, ReportDocumentMainDO entity) throws IOException {
//        boolean updateDocFileFlag = true;
        boolean createIworkWorkflowFlag = false;
        JSONArray bpmFieldExtensions = variables.getJSONArray("bpmFieldExtensions");
        if(bpmFieldExtensions == null)
            bpmFieldExtensions = new JSONArray();
        for(int i = 0; i < bpmFieldExtensions.size(); i++){
            JSONObject extension = bpmFieldExtensions.getJSONObject(i);
            String fieldName = extension.getString("fieldName");
            String stringValue = extension.getString("stringValue");
            if(ObjectUtils.isEmpty(stringValue))
                stringValue = "";
            if(fieldName.equalsIgnoreCase("createiworkflow") && stringValue.equals("1")){
                createIworkWorkflowFlag = true;
                break;
            }
        }
        ReportDocumentFileDO docFile = generatePdf(entity);
        if(createIworkWorkflowFlag){
            CommonResult<IWorkOperationRespDTO> iworkkResult = createIWorkflow(entity, docFile);
            log.error("iworkkResult: " + JSONObject.toJSONString(iworkkResult));
        }
    }

    /*
     * 发起iwork用印*/
    public CommonResult<IWorkOperationRespDTO> createIWorkflow(ReportDocumentMainDO entity, ReportDocumentFileDO docFile) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//        IWorkWorkflowCreateReqDTO dto = new IWorkWorkflowCreateReqDTO();
        IWorkGenericWorkflowCreateReqDTO dto = new IWorkGenericWorkflowCreateReqDTO();
        DictionaryBusinessRespVO dicVo = dictionaryBusinessService.getDataByDataKey("report_doc_iwork_conf").getData();
        String report_doc_iwork_conf = "";
        if(dicVo != null)
            report_doc_iwork_conf = dicVo.getCustomConfig();
        if(ObjectUtils.isEmpty(report_doc_iwork_conf)){
            String msg = "业务参数字典缺少用印iwork配置，配置key：report_doc_iwork_conf";
            log.error(msg);
            throw new RuntimeException(msg);
        }
        JSONObject jsonObject = JSONObject.parseObject(report_doc_iwork_conf);
        String operatorUserId = jsonObject.getString("iwork_operatorUserId");  //iWork 操作人用户编号
        String jbr = jsonObject.getString("iwork_jbr");             //用印申请人
        String yybm = jsonObject.getString("iwork_yybm");               //用印部门
        String fb = jsonObject.getString("iwork_fb");                 //用印单位
        //读取文件url
        CommonResult<FileRespDTO> ret1 = fileApi.getFile(docFile.getFileId());
        String url = docFile.getUrl();
        if(ret1.isSuccess())
            url = ret1.getData().getUrl();
        try {
            url = URLDecoder.decode(url, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        String billNo = entity.getDocumentCode();
        dto.setOperatorUserId(operatorUserId);

        Map<String, Object> payload = new HashMap<>();
        payload.put("sqr", jbr);            //申请人
        payload.put("sqrq", sdf.format(new Date()));    //申请日期
        payload.put("sqgs", fb);            //申请公司
        payload.put("sqbm", yybm);          //申请部门
        payload.put("sjly", iwork_sjly);    //数据来源
        payload.put("ywxtdjbh", billNo);    //业务系统单据编号
        payload.put("yyfs", "1");    //用印方式
//        payload.put("yysyhnrzy", "检测报告用印");
        payload.put("xyywj", url);
        Map<String, Object> param = this.buildCreatePayload( billNo, jsonObject.getString("iwork_workflowId"), new JSONObject(payload));
        JSONObject otherParams = new JSONObject();
        otherParams.put("isnextflow", "0");
        param.put("otherParams", otherParams);
        dto.setPayload( param);
        dto.setWorkflowId(jsonObject.getLong("iwork_workflowId"));

//        dto.setJbr(jbr);
//        dto.setYybm(yybm);
//        dto.setFb(fb);
//        dto.setSqsj(sdf.format(new Date()));
//        dto.setYyqx("检测报告用印");
//        dto.setYysy("检测报告用印");
//        dto.setYysx("检测报告用印");
//        dto.setXyywjUrl(url);
        dto.setYwxtdjbh(billNo);
        dto.setBizCallbackKey(ReportDocListenerConstant.IWORK_BIZ_CALL_BACK_KEY);   //业务回调标识，回调分发使用
//        CommonResult<IWorkOperationRespDTO> iworkResult = iWorkIntegrationApi.createWorkflow(dto);
        CommonResult<IWorkOperationRespDTO> iworkResult = iWorkIntegrationApi.createGenericWorkflow(dto);
        return iworkResult;
    }

    /*
    * 通过处理后的数据和模板id，生成pdf
    * */
    public byte[] generateReportPDF(JSONArray data, Long templateId) throws IOException {
        DataTemplateDO templateDO = dataTemplateService.getDataTemplate(templateId);
        String templateContent = templateDO.getFormContent();
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("Template", templateContent);
        bodyJson.put("Data", data.toJSONString());
        String bodyStr = bodyJson.toJSONString();
//        log.info("html2pdf body: " + bodyStr);
        log.info("html2pdf--start at {}", LocalDateTime.now());
        HttpResponse response = HttpUtil.createPost(html2pdfAddr)
                .body(bodyStr)
                .timeout(15000)
                .execute();
        if (response.getStatus() != 200) {
            // 尝试读取错误响应体以便调试（注意：如果流已消费则无法再次读取，这里 bodyStream 还没读）
            String errorBody = response.body(); 
            log.error("HTML2PDF 服务返回错误状态码: {}, 响应内容: {}", response.getStatus(), errorBody);
            throw new IOException("生成 PDF 失败，远程服务返回状态码: " + response.getStatus() + ", 详情: " + errorBody);
        }

        // 只有状态码为 200 时，才读取流
        InputStream inputStream = response.bodyStream();
        if (inputStream == null) {
            throw new IOException("生成 PDF 失败，响应流为空");
        }

        byte[] pdfBytes = IOUtils.toByteArray(inputStream);
        
        // 【可选防御性检查】验证返回的数据是否真的像 PDF (以 %PDF 开头)
        if (pdfBytes.length < 5 || !(new String(pdfBytes, 0, 4).startsWith("%PDF"))) {
            log.error("生成的 PDF 数据头校验失败，前100字节: {}", new String(pdfBytes, 0, Math.min(100, pdfBytes.length)));
            throw new IOException("生成的文件不是有效的 PDF 格式，可能是服务端返回了错误信息");
        }

        log.info("html2pdf--end at {}, 文件大小: {} bytes", LocalDateTime.now(), pdfBytes.length);
        return pdfBytes;
    }

    /*
     * 生成新版pdf文件
     * 在reportDocumentFile创建新pdf文件
     * */
    @Transactional(rollbackFor = Exception.class)
    public ReportDocumentFileDO generatePdf(ReportDocumentMainDO mainDO) throws IOException {
        String pageFlag = "1";  //分页处理
        Long typeId = mainDO.getReportDocumentTypeId();
        ReportDocumentTypeDO typeDO = reportDocumentTypeService.getReportDocumentType(typeId);
        Long templateId = mainDO.getDataTemplateId();

        CommonResult<JSONArray> result = reportDocumentDataService.assembleDynamicData(mainDO, typeDO, pageFlag);
        JSONArray data = result.getData();
        byte[] fileBytes = generateReportPDF(data, templateId);
        String formDataStr = mainDO.getFormData();
        JSONObject formData = JSONObject.parseObject(formDataStr);
        String entrustCode = "";
        String sampleCategory = "";
        String filename = "检测报告";
        if(!ObjectUtils.isEmpty(formData)){
            entrustCode = formData.getString("entrustCode");
            sampleCategory = formData.getString("sampleCategory");
            if(!ObjectUtils.isEmpty(entrustCode))
                filename = entrustCode;
            if(!ObjectUtils.isEmpty(sampleCategory))
                filename = filename + "(" + sampleCategory + ")";
        }
        filename += ".pdf";
        //上传到文件服务
        FileCreateReqDTO fileCreateReqDTO = new FileCreateReqDTO();
        fileCreateReqDTO.setName(filename);
        fileCreateReqDTO.setDirectory(null);
        fileCreateReqDTO.setType(null);
        fileCreateReqDTO.setContent(fileBytes);
        CommonResult<FileRespDTO> fileResult = fileApi.createFileWithReturn(fileCreateReqDTO);
        if (fileResult == null || !fileResult.isSuccess() || fileResult.getData() == null) {
            throw new ServiceException(REPORT_DOCUMENT_FILE_NOT_EXISTS.getCode(), "通过文件服务创建附件失败: " + Optional.ofNullable(fileResult).map(CommonResult::getMsg).orElse("未知错误"));
        }
        FileRespDTO fileRespDTO = fileResult.getData();
        //创建businessFile
        BusinessFileSaveReqDTO businessFileSaveReqDTO = BusinessFileSaveReqDTO.builder()
                .businessId(mainDO.getId())
                .businessCode(mainDO.getDocumentCode())
                .fileName(filename)
                .fileId(fileRespDTO.getId())
                .source(ReportDocConstant.REPORT_DOCUMENT_BUSINESS_FILE_SOURCE_QMS)
                .status(1)
                .build();
        businessFileApi.createBusinessFile(businessFileSaveReqDTO);

        //写入ReportDocumentFile
        ReportDocumentFileSaveReqVO fileSaveReqVO = new ReportDocumentFileSaveReqVO();
        fileSaveReqVO.setMainId(mainDO.getId());
        fileSaveReqVO.setFileId(fileRespDTO.getId());
        fileSaveReqVO.setName(filename);
        fileSaveReqVO.setPath(fileRespDTO.getDirectory());
        fileSaveReqVO.setUrl(fileRespDTO.getUrl());
        fileSaveReqVO.setVersion(mainDO.getDocumentVersion());
        fileSaveReqVO.setType(ReportDocConstant.REPORT_DOCUMENT_BUSINESS_FILE_SOURCE_QMS);
        reportDocumentFileService.createReportDocumentFile(fileSaveReqVO);
        return BeanUtils.toBean(fileRespDTO, ReportDocumentFileDO.class);
    }


    private Map<String, Object> buildCreatePayload(String billNo, String workflowId, JSONObject payload) {
        LinkedHashMap var2 = new LinkedHashMap();
        var2.put("requestName", "公司用印申请（新版）-" + billNo);
        var2.put("workflowId", workflowId);
        var2.put("mainData", this.buildSealMainData(payload));
        return var2;
    }

    private List<Map<String, Object>> buildSealMainData(JSONObject payload) {
        ArrayList target = new ArrayList();
        String allFields = "sqr,sqrq,sqgs,sqbm,bizId,yysyhnrzy,sjly,ywxtdjbh,yyfs";
        for(String field : allFields.split(",")){
            this.addField(target, field, payload.getString( field));
        }
        this.addJsonField(target, "xyywj", this.buildSealAttachmentValue(payload.getString("xyywj")));
        return target;
    }

    private List<Map<String, Object>> buildSealAttachmentValue(String xyywjUrl) {
        String var2 = this.trimToNull(xyywjUrl);
        if (var2 == null) {
            return null;
        } else {
            LinkedHashMap var3 = new LinkedHashMap(2);
            String var4 = this.extractFileNameFromUrl(var2);
            var3.put("fileName", var4);
            var3.put("filePath", var2);
            ArrayList var5 = new ArrayList(1);
            var5.add(var3);
            return var5;
        }
    }

    private String extractFileNameFromUrl(String url) {
        String var2 = this.trimToNull(url);
        if (var2 == null) {
            return null;
        } else {
            int var3 = var2.indexOf(63);
            String var4 = var3 >= 0 ? var2.substring(0, var3) : var2;
            int var5 = var4.lastIndexOf(47);
            return var5 >= 0 && var5 < var4.length() - 1 ? var4.substring(var5 + 1) : var4;
        }
    }
    private String trimToNull(String value) {
        if (!StringUtils.hasText(value)) {
            return null;
        } else {
            String var2 = value.trim();
            return var2.isEmpty() ? null : var2;
        }
    }

    private void addField(List<Map<String, Object>> target, String name, String value) {
        if (StringUtils.hasText(value)) {
            HashMap var4 = new HashMap(2);
            var4.put("fieldName", name);
            var4.put("fieldValue", value);
            target.add(var4);
        }
    }

    private void addJsonField(List<Map<String, Object>> target, String name, Object value) {
        if (value != null) {
            HashMap var4 = new HashMap(2);
            var4.put("fieldName", name);
            var4.put("fieldValue", value);
            target.add(var4);
        }
    }

}
