package com.hzya.frame.grpU8.nxproof.oerdjml.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hzya.frame.grpU8.nxproof.oerdjjsfs.entity.OerDjjsfsEntity;
import com.hzya.frame.grpU8.nxproof.oerdjml.dto.FileInfoDTO;
import com.hzya.frame.grpU8.nxproof.oerdjml.entity.OerDjmlEntity;
import com.hzya.frame.grpU8.nxproof.oerdjml.service.IOerDjmlExtService;
import com.hzya.frame.grpU8.nxproof.oerdjnr.entity.OerDjnrEntity;
import com.hzya.frame.grpU8.nxproof.oeryszb.entity.OerYszbEntity;
import com.hzya.frame.seeyon.entity.CollAttachmentResDTO;
import com.hzya.frame.seeyon.enums.ColEventTypeEnum;
import com.hzya.frame.seeyon.util.RestUtil;
import com.hzya.frame.sysnew.application.database.entity.SysApplicationDatabaseEntity;
import com.hzya.frame.sysnew.application.database.service.ISysApplicationDatabaseService;
import com.hzya.frame.sysnew.application.entity.SysApplicationEntity;
import com.hzya.frame.sysnew.application.entity.SysExtensionApiEntity;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @Description 扩展类，api接口上配置的扩展方法
 * @Author xiangerlin
 * @Date 2024/8/16 13:45
 **/
@Service(value = "oerDjmlExtServiceImpl")
public class OerDjmlExtServiceImpl implements IOerDjmlExtService {

    Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private RestUtil restUtil;
    @Value("${savefile.path:}")
    public String DSK;
    @Autowired
    private ISysApplicationDatabaseService sysApplicationDatabaseService;
    /**
     * 保存方法前，先调这个方法 组装参数
     *
     * @param entity
     * @return
     */
    @Override
    public SysExtensionApiEntity saveExpensePre(SysExtensionApiEntity entity) {
        try {
            String bodys = entity.getBodys();
            String grpDataSourceCode = "";
            SysApplicationEntity receiveApp = entity.getReceiveApp();
            if (null != receiveApp){
                SysApplicationDatabaseEntity sysDatabaseEntity = new SysApplicationDatabaseEntity();
                sysDatabaseEntity.setAppId(receiveApp.getId());
                List<SysApplicationDatabaseEntity> dataBaseList = sysApplicationDatabaseService.query(sysDatabaseEntity);
                if (CollectionUtils.isNotEmpty(dataBaseList)){
                    grpDataSourceCode = dataBaseList.get(0).getSourceCode();
                }
            }
            Map<String, String> headers = entity.getHeaders();
            String formmainTableName = headers.get("formmainTableName");
            String forsonTableName = headers.get("forsonTableName");
            String djlx = headers.get("djlx");
            JSONObject bodyObj =  JSONObject.parseObject(bodys);
            //事件类型
            String eventType = bodyObj.getString("eventType");
            //summaryId
            String summaryId = bodyObj.getString("summaryId");
            JSONObject seeyonData = bodyObj.getJSONObject("businessDataStr");
            if (null != seeyonData){
                /**
                 * 流程发起 保存/更新单据 要全部数据
                 * 流程撤销 只更新状态，传单号和状态就好了
                 * 流程终止 只更新状态，传单号和状态就好了
                 * 流程结束 更新状态 并上传附件
                 */
                JSONObject formmainData = seeyonData.getJSONObject(formmainTableName);
                JSONArray forsonData = seeyonData.getJSONArray(forsonTableName);
                String res = "";
                if (DjlxEnum.TRAVEL.type.equals(djlx)) {
                    //差旅报销 travel
                    res = travel(headers,eventType,summaryId,grpDataSourceCode,formmainData,forsonData);
                }else if(DjlxEnum.EXPENSE.type.equals(djlx)){
                    //费用报销 expense
                    res = expense(headers,eventType,summaryId,grpDataSourceCode, formmainData, forsonData);
                }else if (DjlxEnum.LABOR.type.equals(djlx)){
                    //劳务费 labor
                }
                if (StrUtil.isNotEmpty(res)){
                    entity.setBodys(res);
                    return entity;
                }
            }
        }catch (Exception ex ){
            logger.error("保存报销单之前组装参数出错",ex);
        }
        return null;
    }

    /**
     * 费用报销单
     * @param headers 请求头
     * @param eventType 事件类型
     * @param summaryId 流程id
     * @param dataSourceCode
     * @param formmainData 主表数据
     * @param forsonData 子表数据
     */
    private String expense(Map<String, String> headers, String eventType,String summaryId, String dataSourceCode,JSONObject formmainData, JSONArray forsonData) {
        String djlxid = headers.get("djlxid");
        String flowcode = headers.get("flowcode");
        String fileApiCode = headers.get("file_api_code");
        OerDjmlEntity djml = new OerDjmlEntity();
        djml.setLclb(eventType);
        djml.setDjbh(formmainData.getString("field0001"));
        djml.setDjlxId(djlxid);
        djml.setDataSourceCode(dataSourceCode);
        JSONObject forsonData0 = forsonData.getJSONObject(0);
        //流程发起
        if (ColEventTypeEnum.ONSTART.getType().equals(eventType)){
            djml.setGsdm("");
            djml.setKjnd("");
            djml.setZt("2");
            djml.setCrerdm("");
            djml.setCrermc("");
            djml.setCrerdate(timestampConvert(formmainData.getString("start_date"),"yyyyMMdd"));
            djml.setDjdate(timestampConvert(formmainData.getString("field0016"),"yyyyMMdd"));
            djml.setJe(formmainData.getString("field0052"));
            djml.setJedx(formmainData.getString("field0071"));
            djml.setYjje("0.00");
            djml.setThje("0.00");
            djml.setBlje(formmainData.getString("field0052"));
            djml.setFjs(formmainData.getString("field0018"));
            djml.setZy(formmainData.getString("field0027"));
            djml.setBmdm("");
            djml.setBmmc("");
            djml.setXmdm("");
            djml.setXmmc("");
            djml.setGrdm("");
            djml.setGrmc("");
            djml.setJjdm("");
            djml.setJjmc("");
            djml.setYhzh(forsonData0.getString("field0078"));
            djml.setKhyh(forsonData0.getString("field0077"));
            djml.setCurshjd("-9");
            djml.setNextshjd("999");
            djml.setFlowcode(flowcode);
            djml.setJsfs("");
            djml.setTel("");
            djml.setSsrq(DateUtil.format(formmainData.getDate("startDate"),"yyyyMMddHHmmssSSS"));
            djml.setSsrid("");
            djml.setSsr("");
            //报销明细
            List<OerDjnrEntity> djnrList = new ArrayList<>();
            //结算方式
            List<OerDjjsfsEntity> jsfsList = new ArrayList<>();
            //预算指标
            List<OerYszbEntity> yszbList = new ArrayList<>();
            int xh = 1;
            for (int i = 0; i< forsonData.size(); i++) {
                JSONObject forson = forsonData.getJSONObject(i);
                String gsdm = forson.getString("");
                String kjnd = forson.getString("");
                String je = forson.getString("field0063");
                //单据内容
                OerDjnrEntity djnr = new OerDjnrEntity();
                djnr.setXh(String.valueOf(xh));
                djnr.setGsdm(gsdm);
                djnr.setKjnd(kjnd);
                djnr.setDjlxId(djlxid);
                djnr.setBnxId(headers.get("bxmx_bnxid"));
                djnr.setJe(je);
                djnr.setBmdm("");
                djnr.setBmmc("");
                djnr.setXmdm("");
                djnr.setXmmc("");
                djnr.setJjdm("");
                djnr.setJjmc("");
                djnr.setFzx8dm("");
                djnr.setFzx8mc("");
                djnr.setZbId("");
                djnr.setJflxdm("");
                djnr.setJflxmc("");
                djnr.setZy(forson.getString("field0079"));
                djnr.setFjs(djml.getFjs());
                djnrList.add(djnr);
                //结算方式
                OerDjjsfsEntity jsfs = new OerDjjsfsEntity();
                jsfs.setGsdm(gsdm);
                jsfs.setKjnd(kjnd);
                jsfs.setDjlxId(djlxid);
                jsfs.setBnxid(headers.get("jsfs_bnxid"));
                jsfs.setXh(String.valueOf(xh));
                jsfs.setJsfsdm("");
                jsfs.setJsfsmc("");
                jsfs.setKmdm("");
                jsfs.setKmmc("");
                jsfs.setSkr(forson.getString("field0076"));
                jsfs.setKhyh(forson.getString("field0077"));
                jsfs.setYhzh(forson.getString("field0078"));
                jsfs.setJe(je);
                jsfs.setYh("");
                jsfs.setYhhh("");
                jsfs.setProvince("");
                jsfs.setCity("");
                jsfs.setRytype("");
                jsfs.setYt(forson.getString("field0079"));
                jsfsList.add(jsfs);
                //预算指标
                OerYszbEntity yszb = new OerYszbEntity();
                BeanUtil.copyProperties(djnr,yszb);
                yszb.setBnxId(headers.get("yszb_bnxid"));
                yszb.setZbdm("");
                yszb.setZy(forson.getString("field0079"));
                yszb.setKmdm("");
                yszb.setKmmc("");
                yszb.setXh(String.valueOf(xh));
                yszbList.add(yszb);
                xh++;
            }
        }
        return null;
    }

    /**
     * 差旅报销单
     * @param headers 请求头
     * @param eventType 事件类型
     * @param summaryId 流程id
     * @param dataSourceCode
     * @param formmainData 主表数据
     * @param forsonData 子表数据
     */
    private String travel(Map<String, String> headers, String eventType,String summaryId, String dataSourceCode,JSONObject formmainData, JSONArray forsonData) {
        String djlxid = headers.get("djlxid");
        String flowcode = headers.get("flowcode");
        String fileApiCode = headers.get("file_api_code");
        OerDjmlEntity djml = new OerDjmlEntity();
        djml.setLclb(eventType);
        djml.setDjbh(formmainData.getString("field0001"));
        djml.setDataSourceCode(dataSourceCode);
        //流程发起
        if (ColEventTypeEnum.ONSTART.getType().equals(eventType)){
            JSONObject forjsonData0 = forsonData.getJSONObject(0);
            djml.setGsdm(forjsonData0.getString("field0084"));
            djml.setKjnd(forjsonData0.getString("field0082"));
            djml.setDjlxId(djlxid);
            djml.setZt("2");
            djml.setCrerdm(formmainData.getString("field0107"));
            djml.setCrermc(formmainData.getString("field0114"));
            djml.setCrerdate(timestampConvert(formmainData.getString("start_date"),"yyyyMMdd"));
            djml.setDjdate((timestampConvert(formmainData.getString("field0002"),"yyyyMMdd")));
            djml.setJe(formmainData.getString("field0033"));
            djml.setJedx(formmainData.getString("field0034"));
            djml.setYjje("0.00");
            djml.setThje("0.00");
            djml.setBlje(formmainData.getString("field0080"));
            djml.setFjs( formmainData.getString("field0004"));
            djml.setZy( formmainData.getString("field0009"));
            //部门代码
            djml.setBmdm(formmainData.getString("field0109"));
            djml.setBmmc(formmainData.getString("field0120"));
            //项目代码
            djml.setXmdm(forjsonData0.getString("field0074"));
            djml.setXmmc(forjsonData0.getString("field0075"));
            //个人代码
            djml.setGrdm(formmainData.getString("field0108"));
            djml.setGrmc(formmainData.getString("field0115"));
            //经济代码
            djml.setJjdm("");
            djml.setJjmc("");
            //银行帐号 开户银行
            djml.setYhzh(forjsonData0.getString("field0079"));
            djml.setKhyh(forjsonData0.getString("field0078"));
            //当前审核节点、下个审核节点 ,不在grp审批，是不是不用填了
            djml.setCurshjd("-9");
            djml.setNextshjd("999");
            djml.setFlowcode(flowcode);
            djml.setJsfs(spliceStr(forjsonData0.getString("field0095"), forjsonData0.getString("field0094")));
            //电话，oa上没有
            djml.setTel(formmainData.getString("field0110"));
            djml.setClf_ccr(formmainData.getString("field0113"));
            //送审日期
            djml.setSsrq( DateUtil.format(formmainData.getDate("startDate"),"yyyyMMddHHmmssSSS"));
            djml.setSsrid(formmainData.getString("field0108"));
            djml.setSsr(formmainData.getString("field0115"));
            djml.setClf_cclb(forjsonData0.getString("field0098"));
            //报销明细
            List<OerDjnrEntity> djnrList = new ArrayList<>();
            //结算方式
            List<OerDjjsfsEntity> jsfsList = new ArrayList<>();
            //预算指标
            List<OerYszbEntity> yszbList = new ArrayList<>();
            int xh = 1;
            for (int i = 0; i< forsonData.size(); i++) {
                JSONObject forson = forsonData.getJSONObject(i);
                String gsdm = forson.getString("field0084");
                String kjnd = forson.getString("field0082");
                String je = forson.getString("field0029");
                //单据内容
                OerDjnrEntity djnr = new OerDjnrEntity();
                djnr.setXh(String.valueOf(xh));
                djnr.setGsdm(gsdm);
                djnr.setKjnd(kjnd);
                djnr.setDjlxId(djlxid);
                djnr.setBnxId(headers.get("bxmx_bnxid"));
                djnr.setJe(je);
                djnr.setBmdm(forson.getString("field0088"));
                djnr.setBmmc(forson.getString("field0087"));
                djnr.setXmdm(forson.getString("field0074"));
                djnr.setXmmc(forson.getString("field0075"));
                djnr.setJjdm("");
                djnr.setJjmc("");
                //grp库里有，不知道是什么 1001基本支出 2001项目支出（网银）
                djnr.setFzx8dm("");
                djnr.setFzx8mc("");
                //指标id
                djnr.setZbId(forson.getString("field0085"));
                djnr.setJflxdm("");
                djnr.setJflxmc("");
                djnr.setZy(forson.getString("field0030"));
                djnr.setClf_startdate(timestampConvert(forson.getString("field0016"),"yyyy-MM-dd"));
                djnr.setClf_enddate(timestampConvert(forson.getString("field0017"),"yyyy-MM-dd"));
                djnr.setClf_ccdd(forson.getString("field0019"));
                djnr.setClf_ccksd(forson.getString("field0018"));
                djnr.setClf_djzs(djml.getFjs());
                djnr.setClf_ccts(forson.getString("field0023"));
                djnr.setClf_cctsbz(forson.getString("field0023"));
                djnr.setClf_ccrs(forson.getString("field0021"));
                djnr.setClf_zw(forson.getString("field0092"));
                djnr.setClf_jtgj(forson.getString("field0119"));
                //住宿费
                djnr.setClf_zsbz(forson.getString("field0070"));
                djnr.setClf_zsf(forson.getString("field0025"));
                //伙食补助
                djnr.setClf_hsbz(forson.getString("field0026"));
                djnr.setClf_hsf(forson.getString("field0116"));
                //交通补助
                djnr.setClf_jtbz(forson.getString("field0024"));
                djnr.setClf_jtbzf(forson.getString("field0117"));
                djnr.setClf_jtf(forson.getString("field0117"));
                //其他
                djnr.setClf_qtf(forson.getString("field0028"));
                //公杂

                djnr.setFjs(djml.getFjs());
                djnrList.add(djnr);
                //结算方式
                OerDjjsfsEntity jsfs = new OerDjjsfsEntity();
                jsfs.setGsdm(gsdm);
                jsfs.setKjnd(kjnd);
                jsfs.setDjlxId(djlxid);
                jsfs.setBnxid(headers.get("jsfs_bnxid"));
                jsfs.setXh(String.valueOf(xh));
                jsfs.setJsfsdm(forson.getString("field0095"));
                jsfs.setJsfsmc(forson.getString("field0094"));
                jsfs.setKmdm(forson.getString("field0089"));
                jsfs.setKmmc(forson.getString("field0066"));
                jsfs.setSkr(forson.getString("field0096"));
                jsfs.setKhyh(forson.getString("field0078"));
                jsfs.setYhzh(forson.getString("field0079"));
                jsfs.setJe(je);
                jsfs.setYh("");
                jsfs.setYhhh("");
                jsfs.setProvince("");
                jsfs.setCity("");
                //支付方式为个人、公务卡时 可以选择 经办人、负责人、其他
                jsfs.setRytype("");
                //oa没有
                jsfs.setYt(forson.getString("field0030"));
                jsfsList.add(jsfs);
                //预算指标
                OerYszbEntity yszb = new OerYszbEntity();
                BeanUtil.copyProperties(djnr,yszb);
                yszb.setBnxId(headers.get("yszb_bnxid"));
                yszb.setZbdm(forson.getString("field0085"));
                yszb.setZy(forson.getString("field0111"));
                yszb.setKmdm(forson.getString("field0089"));
                yszb.setKmmc(forson.getString("field0066"));
                yszb.setXh(String.valueOf(xh));
                yszbList.add(yszb);
                xh++;
            }
            logger.info("报销单主表:{}",JSONObject.toJSONString(djml));
            logger.info("报销单明细表:{}",JSONObject.toJSONString(djnrList));
            logger.info("报销单结算方式:{}",JSONObject.toJSONString(jsfsList));
            logger.info("报销单预算指标:{}",JSONObject.toJSONString(yszbList));
            djml.setOerDjnrEntityList(djnrList);
            djml.setOerDjjsfsEntityList(jsfsList);
            djml.setOerYszbEntityList(yszbList);
        }else if (ColEventTypeEnum.ONSTOP.getType().equals(eventType)){
            //流程终止 修改状态，释放指标
            djml.setZt("0");
            djml.setCurshjd("0");
            djml.setNextshjd("-9");
            djml.setSsrid(null);
            djml.setSsr(null);
            djml.setSsrq(null);
            djml.setShrId(null);
            djml.setShrq(null);
        }else if (ColEventTypeEnum.ONCANCEL.getType().equals(eventType)){
            //流程撤销 修改状态，释放指标
            djml.setZt("1");
            djml.setCurshjd("0");
            djml.setNextshjd("-9");
            djml.setSsrid(null);
            djml.setSsr(null);
            djml.setSsrq(null);
            djml.setShrId(null);
            djml.setShrq(null);
        }else if (ColEventTypeEnum.ONPROCESSFINISHED.getType().equals(eventType)){
            //流程结束事件
            djml.setZt("3");
            djml.setCurshjd("999");
            djml.setNextshjd("-1");
            //查询协同附件
            List<FileInfoDTO> fileInfoList = fileDownload(summaryId, fileApiCode);
            djml.setFileInfoList(fileInfoList);
        }
        String djmlStr = JSONObject.toJSONString(djml);
        logger.info("差旅报销单报文：{}",djmlStr);
        return djmlStr;
    }

    /**
     * 时间戳转成  指定格式
     * @param timestamp 时间戳
     * @param format 格式
     * @return
     */
    private String timestampConvert(String timestamp,String format){
        if (StrUtil.isNotEmpty(timestamp) && NumberUtil.isNumber(timestamp)){
            try {
                DateTime date = DateUtil.date(Long.valueOf(timestamp));
                String formattedDate = DateUtil.format(date, "yyyyMMdd");
                return formattedDate;
            }catch (Exception e){
                logger.error("日期转换出错:{}",e);
            }
        }
        return timestamp;
    }

    /**
     * 附件下载并压缩成zip
     * @param summaryId
     * @param apiCode
     * @return
     */
    private List<FileInfoDTO> fileDownload(String summaryId,String apiCode){
        try {
            List<CollAttachmentResDTO> colAttachmentList = restUtil.getColAttachments(summaryId, "0", apiCode, null);
            //下载协同附件
            if (CollectionUtils.isNotEmpty(colAttachmentList)){
                String token = restUtil.getToken(null, apiCode);
                List<FileInfoDTO> fileList = new ArrayList<>();
                for (CollAttachmentResDTO att : colAttachmentList) {
                    FileInfoDTO fileInfoDTO = new FileInfoDTO();

                    String fileName = URLDecoder.decode(att.getFilename(), "UTF-8");
                    byte[] bytes = restUtil.downloadFileBytes(null, apiCode, att.getFileUrl(), fileName,token);
                    if (!FileUtil.isDirectory(DSK+ File.separator+DateUtil.today())){
                        FileUtil.mkdir(DSK+ File.separator+DateUtil.today());
                    }
                    String filePath = DSK+ File.separator+DateUtil.today()+File.separator+att.getFileUrl()+"."+att.getExtension();
                    File file = new File(filePath);
                    // 使用 FileOutputStream 写入字节数组到文件
                    try (FileOutputStream fos = new FileOutputStream(file)) {
                        fos.write(bytes);
                    }
                    if (null != file){
                        String zipPath = DSK+File.separator+DateUtil.today()+File.separator+att.getFileUrl()+".zip";
                        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipPath), Charset.forName("GBK"));
                        writeZipFile(file, zos, fileName);
                        zos.close();
                        // 获取压缩文件的字节数组
                        File zipFile = new File(zipPath);
                        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream((int) zipFile.length());
                        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(zipFile));
                        int buf_size = 1024;
                        byte[] buffer = new byte[buf_size];
                        int len = 0;
                        while (-1 != (len = bufferedInputStream.read(buffer, 0, buf_size))) {
                            byteArrayOutputStream.write(buffer, 0, len);
                        }
                        byte[] fileByte = byteArrayOutputStream.toByteArray();
                        fileInfoDTO.setData(fileByte);
                        fileInfoDTO.setFile_size(att.getSize());
                        fileInfoDTO.setFile_name(fileName);
                        fileList.add(fileInfoDTO);
                    }
                }
                return fileList;
            }
        }catch (Exception e){
            logger.error("下载附件出错:{}",e);
        }
        return null;
    }
    /**
     * 把文件压缩成zip
     * @param file 要压缩的文件
     * @param zos 文件压缩流
     * @param fileName 文件名
     */
    private void writeZipFile(File file, ZipOutputStream zos, String fileName) {
        if (null != file && null != zos) {
            try {
                logger.info("=====压缩文件=====");
                zos.putNextEntry(new ZipEntry(fileName));
                FileInputStream fos = new FileInputStream(file);
                BufferedInputStream bis = new BufferedInputStream(fos);
                int len;
                byte[] buf = new byte[1024];
                while ((len = bis.read(buf, 0, 1024)) != -1) {
                    zos.write(buf, 0, len);
                }
                bis.close();
                fos.close();
                logger.info("=====压缩完成=====");
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("=====压缩文件出错=====");
            }
        }
    }

    /**
     * code和name拼接[]
     * @param code
     * @param name
     * @return 格式：03[公务卡]
     */
    private String spliceStr(String code,String name){
        String template = "{}[{}]";
        return StrUtil.format(template,code,name);
    }

    public enum DjlxEnum {
        TRAVEL("travel","差旅报销单"),
        EXPENSE("expense","费用报销单"),
        LABOR("labor","劳务费报销单"),
        ;

        private String type;
        private String name;

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        DjlxEnum(String type, String name) {
            this.type = type;
            this.name = name;
        }
    }

}
