package com.docus.server.message.busservice.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.docus.core.util.DateUtil;
import com.docus.core.util.Func;
import com.docus.infrastructure.core.exception.BaseException;
import com.docus.infrastructure.redis.service.IdService;
import com.docus.server.message.busservice.ZxjhBusinessService;
import com.docus.server.message.config.AssortConfig;
import com.docus.server.message.config.QueryConfig;
import com.docus.server.message.dto.*;
import com.docus.server.message.entity.TBasicExcel;
import com.docus.server.message.entity.TScanAssort;
import com.docus.server.message.mapper.ZxjhMapper;
import com.docus.server.message.util.XmlUtil;
import com.itextpdf.text.pdf.PdfReader;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.namespace.QName;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.*;
import java.util.*;

/**
 * @BelongsProject: docus-unified-message
 * @BelongsPackage: com.docus.server.message.busservice.impl
 * @Author: chierhao
 * @CreateTime: 2024-03-20  08:57
 * @Description: TODO
 * @Version: 1.0
 */
@Slf4j
@Service
public class ZxjhBusinessServiceImpl implements ZxjhBusinessService {

    @Autowired
    private ZxjhMapper zxjhMapper;

    @Autowired
    private IdService idService;

    @Override
    public void wsRecordDown() {
        QueryConfig.Config config = QueryConfig.getConfig();
        if (config == null) {
            throw new BaseException("未配置查询配置");
        }
        List<AssortConfig.Config> assortConfig = AssortConfig.getConfig();
        if (assortConfig == null) {
            throw new BaseException("未配置分段配置");
        }
        Date disDates = DateUtil.parse(config.getDisDates(), "yyyy-MM-dd HH:mm:ss");
        Date disDatee = DateUtil.parse(config.getDisDatee(), "yyyy-MM-dd HH:mm:ss");

        List<TBasicExcel> basicDatas = zxjhMapper.getBasicData("5", disDates, disDatee);
        log.info("查询基础数据条数：{}",basicDatas.size());
        if(basicDatas.size()==0){
            return;
        }
        List<JSONObject> paramsConfig = config.getParams();

        for (TBasicExcel basicData : basicDatas) {
            String patientId = basicData.getPatientId();
            String jzh = basicData.getJzh();
            log.info("同步病案主键:{}，jzh:{}开始",patientId,jzh);

            try {
                List<JSONObject> params = new ArrayList<>();
                for (JSONObject jsonObject : paramsConfig) {
                    if(jsonObject.getString("name").equals("data")){
                        JSONObject param=new JSONObject();
                        param.put("name",jsonObject.getString("name"));
                        String value = jsonObject.getString("value");
                        String format = String.format(value, jzh);
                        param.put("value",format);
                        params.add(param);
                        continue;
                    }
                    params.add(jsonObject);
                }
                String result = requestFunctionWebServiceCXF(config.getUrl(),config.getTargetNamespace(),config.getMethod(),params);
                if(Func.isEmpty(result)){
                    throw new BaseException("result为空");
                }
                List<FileDto> fileDtos = getFileDtos(result);
                log.info("同步病案主键:{}，jzh:{},文件数量:{}",patientId,jzh,fileDtos.size());
                if(Func.isEmpty(fileDtos)){
                    continue;
                }
                String downPath=config.getDownPath()+File.separator+patientId;
                List<TScanAssort> tScanAssorts=new ArrayList<TScanAssort>();
                for (FileDto fileDto : fileDtos) {
                    TScanAssort tScanAssort=new TScanAssort();
                    tScanAssort.setId(idService.getDateSeq());
                    tScanAssort.setImagePath(downPath);
                    tScanAssort.setFileStorageType(1);
                    tScanAssort.setSource("-5");
                    tScanAssort.setPatientId(patientId);
                    tScanAssort.setFileTitle(fileDto.getPMR_NAME());
                    tScanAssort.setAssortId(getAssortId(fileDto.getEMR_TYPE_CODE(),assortConfig));
                    tScanAssort.setCreateTime(new Date());
                    downFile(tScanAssort,fileDto.getPMR_URL(),downPath);
                    tScanAssorts.add(tScanAssort);
                }
                zxjhMapper.delete(patientId);
                zxjhMapper.saveAssort(tScanAssorts);
                log.info("同步病案主键:{}，jzh:{}结束",patientId,jzh);
            }catch (Exception e) {
                log.error(e.getMessage(), e);
                zxjhMapper.saveLog(patientId,e.getMessage());
            }
        }
    }

    @Override
    public void tScanAssortSave(String patientId) {
        String jzh = zxjhMapper.getJzh(patientId);
        if(Func.isEmpty(jzh)){
            throw new BaseException("jzh为空，或者病案不存在");
        }
        QueryConfig.Config config = QueryConfig.getConfig();
        if (config == null) {
            throw new BaseException("未配置查询配置");
        }
        List<AssortConfig.Config> assortConfig = AssortConfig.getConfig();
        if (assortConfig == null) {
            throw new BaseException("未配置分段配置");
        }
        List<JSONObject> paramsConfig = config.getParams();
        log.info("同步病案主键:{}，jzh:{}开始",patientId,jzh);
        try {
            List<JSONObject> params = new ArrayList<>();
            for (JSONObject jsonObject : paramsConfig) {
                if(jsonObject.getString("name").equals("data")){
                    JSONObject param=new JSONObject();
                    param.put("name",jsonObject.getString("name"));
                    String value = jsonObject.getString("value");
                    String format = String.format(value, jzh);
                    param.put("value",format);
                    params.add(param);
                    continue;
                }
                params.add(jsonObject);
            }
            String result = requestFunctionWebServiceCXF(config.getUrl(),config.getTargetNamespace(),config.getMethod(),params);
            if(Func.isEmpty(result)){
                throw new BaseException("result为空");
            }
            List<FileDto> fileDtos = getFileDtos(result);
            log.info("同步病案主键:{}，jzh:{},文件数量:{}",patientId,jzh,fileDtos.size());
            if(Func.isEmpty(fileDtos)){
                return;
            }
            String downPath=config.getDownPath()+File.separator+patientId;
            List<TScanAssort> tScanAssorts=new ArrayList<TScanAssort>();
            for (FileDto fileDto : fileDtos) {
                TScanAssort tScanAssort=new TScanAssort();
                tScanAssort.setId(idService.getDateSeq());
                tScanAssort.setImagePath(downPath);
                tScanAssort.setFileStorageType(1);
                tScanAssort.setSource("-5");
                tScanAssort.setPatientId(patientId);
                tScanAssort.setFileTitle(fileDto.getPMR_NAME());
                tScanAssort.setAssortId(getAssortId(fileDto.getEMR_TYPE_CODE(),assortConfig));
                tScanAssort.setCreateTime(new Date());
                downFile(tScanAssort,fileDto.getPMR_URL(),downPath);
                tScanAssorts.add(tScanAssort);
            }
            zxjhMapper.delete(patientId);
            zxjhMapper.saveAssort(tScanAssorts);
            log.info("同步病案主键:{}，jzh:{}结束",patientId,jzh);
        }catch (Exception e) {
            log.error(e.getMessage(), e);
            zxjhMapper.saveLog(patientId,e.getMessage());
        }
    }



    public String getAssortId(String EMR_TYPE_CODE,List<AssortConfig.Config> assortConfig){
        String assortId="";
        String defaut="";
        for (AssortConfig.Config config : assortConfig) {
            if(EMR_TYPE_CODE.equals(config.getEmrTypeCode())){
                assortId=config.getAssortId();
            }
            if("defaut".equals(config.getEmrTypeCode())){
                defaut=config.getAssortId();
            }
        }
        if(assortId.equals("")){
            assortId=defaut;
        }
        return assortId;
    }

    public String requestFunctionWebServiceCXF(String url, String namespace, String method, List<JSONObject> params) throws Exception {
        String result;
        //创建动态客户端工厂 创建客户端
        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
        Client client = dcf.createClient(url);
        //命名空间和方法
        QName name = new QName(namespace, method);
        // 定义参数
        List paramList=new ArrayList();
        for (JSONObject param:params){
            paramList.add(param.getString("value"));
        }
        // 设置参数值
        log.info("查询入参{}", JSON.toJSONString(paramList));
        Object[] paramArray =  paramList.toArray();
        Object[] objects = client.invoke(name, paramArray);
        result = objects[0].toString();
        return result;
    }

    public List<FileDto> getFileDtos(String str) {
        XmlUtil xml= XmlUtil.of(str);
        //请求结果状态
        String status="0";
        Node statusNode = xml.getNode("/MESSAGE/HEADER/STATUS");
        if(Func.isNotEmpty(statusNode)){
            status=statusNode.getTextContent();
        }
        if(status.equals("0")){
           throw new BaseException(str);
        }
        List<FileDto> list=new ArrayList<FileDto>();
        NodeList rows= xml.getNodeList("/MESSAGE/BODY/ROWS/ROW");
        for (int i = 1; i <= rows.getLength(); i++) {
            Node PMR_ID_NODE=xml.getNode("/MESSAGE/BODY/ROWS/ROW["+i+"]/PMR_ID");
            String PMR_ID=null;
            if(Func.isNotEmpty(PMR_ID_NODE)){
                PMR_ID=PMR_ID_NODE.getTextContent();
            }
            Node PMR_NAME_NODE=xml.getNode("/MESSAGE/BODY/ROWS/ROW["+i+"]/PMR_NAME");
            String PMR_NAME=null;
            if(Func.isNotEmpty(PMR_NAME_NODE)){
                PMR_NAME=PMR_NAME_NODE.getTextContent();
            }
            Node PMR_NAME_NO_NODE=xml.getNode("/MESSAGE/BODY/ROWS/ROW["+i+"]/PMR_NAME_NO");
            String PMR_NAME_NO=null;
            if(Func.isNotEmpty(PMR_NAME_NO_NODE)){
                PMR_NAME_NO =PMR_NAME_NO_NODE.getTextContent();
            }
            Node PMR_URL_NODE=xml.getNode("/MESSAGE/BODY/ROWS/ROW["+i+"]/PMR_URL");
            String PMR_URL=null;
            if(Func.isNotEmpty(PMR_URL_NODE)){
                PMR_URL=PMR_URL_NODE.getTextContent();
            }
            Node RCD_TYPE_CODE_NODE=xml.getNode("/MESSAGE/BODY/ROWS/ROW["+i+"]/RCD_TYPE_CODE");
            String RCD_TYPE_CODE=null;
            if(Func.isNotEmpty(RCD_TYPE_CODE_NODE)){
                RCD_TYPE_CODE =RCD_TYPE_CODE_NODE.getTextContent();
            }
            Node RCD_TYPE_NAME_NODE=xml.getNode("/MESSAGE/BODY/ROWS/ROW["+i+"]/RCD_TYPE_NAME");
            String RCD_TYPE_NAME=null;
            if(Func.isNotEmpty(RCD_TYPE_NAME_NODE)){
                RCD_TYPE_NAME =RCD_TYPE_NAME_NODE.getTextContent();
            }
            Node EMR_TYPE_CODE_NODE=xml.getNode("/MESSAGE/BODY/ROWS/ROW["+i+"]/EMR_TYPE_CODE");
            String EMR_TYPE_CODE=null;
            if(Func.isNotEmpty(EMR_TYPE_CODE_NODE)){
                EMR_TYPE_CODE =EMR_TYPE_CODE_NODE.getTextContent();
            }
            Node EMR_TYPE_NAME_NODE=xml.getNode("/MESSAGE/BODY/ROWS/ROW["+i+"]/EMR_TYPE_NAME");
            String EMR_TYPE_NAME=null;
            if(Func.isNotEmpty(EMR_TYPE_NAME_NODE)){
                EMR_TYPE_NAME =EMR_TYPE_NAME_NODE.getTextContent();
            }
            if(Func.isEmpty(PMR_URL)){
                throw new BaseException("第"+i+"条文件数据文件地址为空");
            }
            FileDto dto= new FileDto();
            dto.setPMR_ID(PMR_ID);
            dto.setPMR_NAME(PMR_NAME);
            dto.setPMR_NAME_NO(PMR_NAME_NO);
            dto.setPMR_URL(PMR_URL);
            dto.setRCD_TYPE_CODE(RCD_TYPE_CODE);
            dto.setRCD_TYPE_NAME(RCD_TYPE_NAME);
            dto.setEMR_TYPE_CODE(EMR_TYPE_CODE);
            dto.setEMR_TYPE_NAME(EMR_TYPE_NAME);
            list.add(dto);
        }
        return list;
    }

    public void downFile(TScanAssort tScanAssort,String sourcePath,String downPath) throws Exception{
        File file = new File(downPath);
        if(!file.exists()){
            file.mkdirs();
        }
        //文件地址形似ftp://AdminPLAT:Plat.2023@192.168.12.90:21/PaperlessData/2024/03/05/Emr/b1162dd9-c47a-4353-8572-37667f6114bc.pdf
        //获取文件后最
        String end = sourcePath.substring(sourcePath.lastIndexOf("."));
        //本地文件名
        String fileName = UUID.randomUUID()+end; // 假设要下载的文件名为example.pdf
        //文件本地存储路径
        String localFilePath = downPath +File.separator+ fileName;

        URI uri = new URI(sourcePath);
        String host = uri.getHost();
        int port = uri.getPort() == -1 ? 21 : uri.getPort(); // 默认端口号为21
        String userInfo = uri.getRawUserInfo();
        String username = "";
        String password = "";
        if(userInfo != null) {
            String[] userInfoArray = userInfo.split(":");
            if(userInfoArray.length >= 1) {
                username = URLDecoder.decode(userInfoArray[0], "UTF-8");
            }
            if(userInfoArray.length >= 2) {
                password = URLDecoder.decode(userInfoArray[1], "UTF-8");
            }
        }
        String path = uri.getPath();
        FTPClient ftpClient = new FTPClient();
        OutputStream outputStream=null;
        try {
            ftpClient.connect(host, port);
            ftpClient.login(username, password);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            File localFile = new File(localFilePath);
            outputStream = new FileOutputStream(localFile);

            ftpClient.retrieveFile(path, outputStream);

            int numberOfPages=0;
            // 判断文件类型并获取页数
            if (isPdf(localFilePath)) {
                numberOfPages = getPdfPageCount(localFilePath);
                tScanAssort.setFileSource(1);
                tScanAssort.setFilePages(numberOfPages);
            } else if (isImage(localFilePath)) {
                numberOfPages=1;
                tScanAssort.setFileSource(2);
                tScanAssort.setFilePages(numberOfPages);
            }
            tScanAssort.setScanPage(fileName);
        } catch (Exception ex) {
            log.error(ex.getMessage(),ex);
            throw new BaseException("下载文件出错");
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.logout();
                    ftpClient.disconnect();
                } catch (Exception ex) {
                    log.error(ex.getMessage(),ex);
                }
            }
            if ( outputStream!=null){
                outputStream.close();
            }
        }
    }

    private static boolean isPdf(String filePath) {
        // 检查文件扩展名是否为.pdf
        return filePath.toLowerCase().endsWith(".pdf");
    }

    private static boolean isImage(String filePath) {
        // 检查文件扩展名是否为常见的图片格式
        return filePath.toLowerCase().endsWith(".png") || filePath.toLowerCase().endsWith(".jpg") || filePath.toLowerCase().endsWith(".jpeg") || filePath.toLowerCase().endsWith(".bmp");
    }

    private static int getPdfPageCount(String filePath) {
        PdfReader reader=null;
        int numberOfPages=0;
        try{
            reader = new PdfReader(filePath);
            numberOfPages = reader.getNumberOfPages();
        } catch (Exception e) {
            log.info(e.getMessage(),e);
            throw new BaseException("获取文件页码出错");
        }finally{
            reader.close();
        }
        return numberOfPages;
    }

    @Override
    public void downFile(String sourcePath, String downPath) throws Exception{
        File file = new File(downPath);
        if(!file.exists()){
            file.mkdirs();
        }
        //文件地址形似ftp://AdminPLAT:Plat.2023@192.168.12.90:21/PaperlessData/2024/03/05/Emr/b1162dd9-c47a-4353-8572-37667f6114bc.pdf
        //获取文件后最
        String end = sourcePath.substring(sourcePath.lastIndexOf("."));
        //本地文件名
        String fileName = UUID.randomUUID()+end; // 假设要下载的文件名为example.pdf
        //文件本地存储路径
        String localFilePath = downPath +File.separator+ fileName;

        URI uri = new URI(sourcePath);
        String host = uri.getHost();
        int port = uri.getPort() == -1 ? 21 : uri.getPort(); // 默认端口号为21
        String userInfo = uri.getRawUserInfo();
        String username = "";
        String password = "";
        if(userInfo != null) {
            String[] userInfoArray = userInfo.split(":");
            if(userInfoArray.length >= 1) {
                username = URLDecoder.decode(userInfoArray[0], "UTF-8");
            }
            if(userInfoArray.length >= 2) {
                password = URLDecoder.decode(userInfoArray[1], "UTF-8");
            }
        }
        String path = uri.getPath();
        FTPClient ftpClient = new FTPClient();
        OutputStream outputStream=null;
        try {
            ftpClient.connect(host, port);
            ftpClient.login(username, password);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);

            File localFile = new File(localFilePath);
            outputStream = new FileOutputStream(localFile);

            ftpClient.retrieveFile(path, outputStream);

        } catch (Exception ex) {
            log.error(ex.getMessage(),ex);
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.logout();
                    ftpClient.disconnect();
                } catch (Exception ex) {
                    log.error(ex.getMessage(),ex);
                }
            }
            if ( outputStream!=null){
                outputStream.close();
            }
        }
    }
}
