package com.ruoyi.framework.manager.factory;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.uuid.Seq;
import com.ruoyi.system.domain.guarantee.GuaranteeInfo;
import com.ruoyi.system.domain.guarantee.GuaranteeInfoFj;
import com.ruoyi.system.domain.loan.LoanApplicationFj;
import com.ruoyi.system.domain.loan.ShareholderFj;
import com.ruoyi.system.mapper.GuaranteeInfoFjMapper;
import com.ruoyi.system.mapper.ShareholderFjMapper;
import com.ruoyi.system.service.guarantee.IGuaranteeInfoFjService;
import com.ruoyi.system.service.loan.ILoanApplicationFjService;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.LogUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.AddressUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.domain.SysLogininfor;
import com.ruoyi.system.domain.SysOperLog;
import com.ruoyi.system.service.ISysLogininforService;
import com.ruoyi.system.service.ISysOperLogService;
import eu.bitwalker.useragentutils.UserAgent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import static com.ruoyi.common.constant.CommonConstants.*;

/**
 * 异步工厂（产生任务用）
 *
 * @author ruoyi
 */

@Component
public class AsyncFactory {
    private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");

    @Autowired
    private static RedisCache redisCache;

    @Autowired
    public void setRedisCache(RedisCache redisCache) {
        AsyncFactory.redisCache = redisCache;
    }

    /**
     * 记录登录信息
     *
     * @param username 用户名
     * @param status   状态
     * @param message  消息
     * @param args     列表
     * @return 任务task
     */
    public static TimerTask recordLogininfor(final String username, final String status, final String message,
                                             final Object... args) {
        final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
        final String ip = IpUtils.getIpAddr();
        return new TimerTask() {
            @Override
            public void run() {
                String address = AddressUtils.getRealAddressByIP(ip);
                StringBuilder s = new StringBuilder();
                s.append(LogUtils.getBlock(ip));
                s.append(address);
                s.append(LogUtils.getBlock(username));
                s.append(LogUtils.getBlock(status));
                s.append(LogUtils.getBlock(message));
                // 打印信息到日志
                sys_user_logger.info(s.toString(), args);
                // 获取客户端操作系统
                String os = userAgent.getOperatingSystem().getName();
                // 获取客户端浏览器
                String browser = userAgent.getBrowser().getName();
                // 封装对象
                SysLogininfor logininfor = new SysLogininfor();
                logininfor.setUserName(username);
                logininfor.setIpaddr(ip);
                logininfor.setLoginLocation(address);
                logininfor.setBrowser(browser);
                logininfor.setOs(os);
                logininfor.setMsg(message);
                // 日志状态
                if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
                    logininfor.setStatus(Constants.SUCCESS);
                } else if (Constants.LOGIN_FAIL.equals(status)) {
                    logininfor.setStatus(Constants.FAIL);
                }
                // 插入数据
                SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
            }
        };
    }

    /**
     * 操作日志记录
     *
     * @param operLog 操作日志信息
     * @return 任务task
     */
    public static TimerTask recordOper(final SysOperLog operLog) {
        return new TimerTask() {
            @Override
            public void run() {
                // 远程查询操作地点
                operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
                SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
            }
        };
    }

    /**
     * 合并图片生成PDF保存为文件
     *
     * @param loanApplicationFjList
     * @return
     */
    public static TimerTask createPdfFromImages(List<LoanApplicationFj> loanApplicationFjList, String loanApplicationNumber) {
        return new TimerTask() {
            @Override
            public void run() {
                String key = "lock:A:" + loanApplicationNumber;
                redisCache.setCacheObject(key, 1, 5, TimeUnit.MINUTES);
                //自定义锁，必须要所有异步任务都跑完才能再次修改
                //根据文件类型进行判断是否需要合成pdf
                Map<String, List<LoanApplicationFj>> bigTypeMap = loanApplicationFjList.stream().collect(Collectors.groupingBy(LoanApplicationFj::getBigType));
                if (bigTypeMap.size() > 0) {
                    List<LoanApplicationFj> loanApplicationFjListA = bigTypeMap.get(A);
                    List<LoanApplicationFj> loanApplicationFjListB = bigTypeMap.get(B);
                    if (loanApplicationFjListA != null && loanApplicationFjListA.size() > 0) {
                        createPdfFromImages(loanApplicationFjList, loanApplicationFjListA, loanApplicationNumber, A);
                    }
                    if (loanApplicationFjListB != null && loanApplicationFjListB.size() > 0) {
                        createPdfFromImages(loanApplicationFjList, loanApplicationFjListB, loanApplicationNumber, B);
                    }
                }
                //自定义锁，必须要所有异步任务都跑完才能再次修改
                redisCache.deleteObject(key);
            }
        };
    }

    /**
     * @param loanApplicationFjList  全体附件
     * @param loanApplicationFjListA 分附件大类集合
     * @return
     */
    public static void createPdfFromImages(List<LoanApplicationFj> loanApplicationFjList, List<LoanApplicationFj> loanApplicationFjListA, String loanApplicationNumber, String bigType) {
        if (loanApplicationFjListA != null && loanApplicationFjListA.size() > 0) {
            Map<String, List<LoanApplicationFj>> typeMap = loanApplicationFjListA.stream().collect(Collectors.groupingBy(LoanApplicationFj::getType));
            List<LoanApplicationFj> list = new ArrayList<>();
            for (String type : typeMap.keySet()) {
                List<LoanApplicationFj> loanApplicationFjListInsert = typeMap.get(type);
                //获取附件名称
                String fjName = loanApplicationFjListInsert.get(0).getName().split("_")[0];
                List<String> typeList = loanApplicationFjListInsert.stream().filter(e -> type.equals(e.getType()) && ("png".equals(e.getName().split("\\.")[1]) || "jpg".equals(e.getName().split("\\.")[1]) || "jpeg".equals(e.getName().split("\\.")[1]))).map(LoanApplicationFj::getUrl).collect(Collectors.toList());
                if (typeList.size() > 0) {
                    for (int i = 0; i < typeList.size(); i++) {
                        ///profile/upload/RZDB202405281147018884551/公司章程_20240528114820A002.png 前缀替换
                        String replaced = typeList.get(i).replace("/profile/upload", RuoYiConfig.getUploadPath());
                        typeList.set(i, replaced);
                    }
                    //先删除原先的pdf数据库记录
                    List<LoanApplicationFj> pdfOne = loanApplicationFjListInsert.stream().filter(e -> ObjectUtils.isNotEmpty(e.getRemark()) && e.getRemark().equals(ONE) && ("pdf".equals(e.getName().split("\\.")[1]))).collect(Collectors.toList());
                    if (pdfOne.size() > 0) {
                        for (LoanApplicationFj loanApplicationFj : pdfOne) {
                            //删除数据库数据
                            SpringUtils.getBean(ILoanApplicationFjService.class).deleteLoanApplicationFjByFjId(loanApplicationFj.getFjId());
                            //删除服务器记录
                            String urlPdf = loanApplicationFj.getUrl();
                            if (StringUtils.isNotBlank(urlPdf)) {
                                String filePath = urlPdf.replace("/profile/upload", RuoYiConfig.getUploadPath());
                                //删除服务器上对应文件
                                File file = new File(filePath);
                                if (file.exists()) {
                                    if (file.delete()) {
                                        System.out.println("删除：" + filePath);
                                    } else {
                                        System.out.println("删除：" + filePath + "失败");
                                    }
                                }
                            }
                        }
                    }
                    createPdfFromImages(list, loanApplicationFjList, typeList, loanApplicationNumber, fjName + "_" + Seq.getId(Seq.uploadSeqType), type, bigType);
                }
            }
            if (list.size() > 0){
                // 插入数据
                SpringUtils.getBean(ILoanApplicationFjService.class).insertLoanApplicationFj(list);
            }
        }
    }

    /**
     * @param imagePaths            图片地址集合
     * @param loanApplicationNumber 申请编号
     * @param originalFilename      pdf文件名称
     * @param type                  文件类型
     */
    public static List<LoanApplicationFj> createPdfFromImages(List<LoanApplicationFj> list, List<LoanApplicationFj> loanApplicationFjList, List<String> imagePaths, String loanApplicationNumber, String originalFilename, String type, String bigType) {
        // 上传文件路径 = 根+申请编号
        String filePath = StringUtils.format("{}/{}/{}.{}", RuoYiConfig.getUploadPath(), loanApplicationNumber,
                FilenameUtils.getBaseName(originalFilename), "pdf");
        //pdf保存位置
        File outPutPdf = new File(filePath);
        try {

            FileUploadUtils.createPdfFromImages(imagePaths, outPutPdf);
            //往附件信息中插入对应PDF数据
            LoanApplicationFj applicationFj = new LoanApplicationFj();
            applicationFj.setLoanApplicationId(loanApplicationFjList.get(0).getLoanApplicationId());
            applicationFj.setLoanApplicationNumber(loanApplicationNumber);
            applicationFj.setName(originalFilename + ".pdf");
            applicationFj.setUrl(StringUtils.format("{}/{}/{}.{}", "/profile/upload", loanApplicationNumber,
                    FilenameUtils.getBaseName(originalFilename), "pdf"));
            applicationFj.setBigType(bigType);
            applicationFj.setType(type);
            //给前端判断是否是系统生成的pdf
            applicationFj.setRemark(ONE);
            list.add(applicationFj);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }


    /**
     * 股东附件合并图片生成PDF保存为文件
     *
     * @param shareholderFjList
     * @return
     */

    public static TimerTask createPdfFromImagesShareholder(List<ShareholderFj> shareholderFjList, String loanApplicationNumber,Long loanApplicationId) {
        return new TimerTask() {
            @Override
            public void run() {
                String key = "lock:B:" + loanApplicationNumber;
                redisCache.setCacheObject(key, 1, 5, TimeUnit.MINUTES);
                List<String> imagePaths = new ArrayList<>();
                //根据文件类型进行判断是否需要合成pdf
                for (ShareholderFj shareholderFj : shareholderFjList) {
                    //获取原先的pdf地址,去服务器上删除要替换路径
                    String shareholderZxUrlPdf = shareholderFj.getShareholderZxUrlPdf();
                    if (StringUtils.isNotBlank(shareholderZxUrlPdf)) {
                        String filePath = shareholderZxUrlPdf.replace("/profile/upload", RuoYiConfig.getUploadPath());
                        //删除服务器上对应文件
                        File file = new File(filePath);
                        if (file.exists()) {
                            if (file.delete()) {
                                System.out.println("删除：" + filePath);
                            } else {
                                System.out.println("删除：" + filePath + "失败");
                            }
                        }
                    }
                    String shareholderZxUrl = shareholderFj.getShareholderZxUrl();
                    if (StringUtils.isNotEmpty(shareholderZxUrl)) {
                        String[] split = shareholderZxUrl.split(",");
                        for (String fileName : split) {
                            if ("png".equals(fileName.split("\\.")[1]) || "jpg".equals(fileName.split("\\.")[1]) || "jpeg".equals(fileName.split("\\.")[1])) {
                                imagePaths.add(fileName);
                            }
                        }
                    }
                    if (imagePaths.size() > 0) {
                        String substring = imagePaths.get(0).substring(imagePaths.get(0).lastIndexOf("/") + 1, imagePaths.get(0).lastIndexOf("_")) + Seq.getId(Seq.uploadSeqType);

                        for (int i = 0; i < imagePaths.size(); i++) {
                            //前缀替换
                            String replaced = imagePaths.get(i).replace("/profile/upload", RuoYiConfig.getUploadPath());
                            imagePaths.set(i, replaced);
                        }

                        // 上传文件路径 = 根+申请编号
                        String filePath = StringUtils.format("{}/{}/{}.{}", RuoYiConfig.getUploadPath(), loanApplicationNumber,
                                FilenameUtils.getBaseName(substring), "pdf");
                        //pdf保存位置
                        File outPutPdf = new File(filePath);
                        try {
                            FileUploadUtils.createPdfFromImages(imagePaths, outPutPdf);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        shareholderFj.setShareholderZxUrlPdf(StringUtils.format("{}/{}/{}.{}", "/profile/upload", loanApplicationNumber,
                                FilenameUtils.getBaseName(substring), "pdf"));
                    }
                }
                //判断是否有股东shareholder_fj_id
                List<ShareholderFj> shareholderFjsInsert = shareholderFjList.stream().filter(e -> ObjectUtils.isEmpty(e.getShareholderFjId())).collect(Collectors.toList());
                if (shareholderFjsInsert.size() > 0) {
                    for (ShareholderFj shareholderFj : shareholderFjsInsert) {
                        shareholderFj.setLoanApplicationId(loanApplicationId);
                        shareholderFj.setLoanApplicationNumber(loanApplicationNumber);
                    }
                    // 新增股东数据
                    SpringUtils.getBean(ShareholderFjMapper.class).batchShareholderFj(shareholderFjsInsert);
                }
                List<ShareholderFj> shareholderFjsUpdate = shareholderFjList.stream().filter(e -> ObjectUtils.isNotEmpty(e.getShareholderFjId())).collect(Collectors.toList());
                if (shareholderFjsUpdate.size() > 0) {
                    for (ShareholderFj shareholderFj : shareholderFjsUpdate) {
                        //更新股东信息
                        SpringUtils.getBean(ShareholderFjMapper.class).updateShareholderFj(shareholderFj);
                    }
                }
                redisCache.deleteObject(key);
            }
        };
    }


    /**
     * 反担保附件合并图片生成PDF保存为文件
     *
     * @param guaranteeInfoList 反担保基础信息集合
     * @return
     */

    public static TimerTask createPdfFromImagesGuaranteeInfo(List<GuaranteeInfo> guaranteeInfoList, String loanApplicationNumber) {
        return new TimerTask() {
            @Override
            public void run() {
                String key = "lock:C:" + loanApplicationNumber;
                redisCache.setCacheObject(key, 1, 5, TimeUnit.MINUTES);
                List<GuaranteeInfoFj> list = new ArrayList();
                //根据文件类型进行判断是否需要合成pdf
                for (GuaranteeInfo guaranteeInfo : guaranteeInfoList) {
                    Long loanApplicationId = guaranteeInfo.getLoanApplicationId();
                    Long guaranteeInfoId = guaranteeInfo.getGuaranteeInfoId();
                    //所有反担保信息的附件
                    List<GuaranteeInfoFj> guaranteeInfoFjList = guaranteeInfo.getGuaranteeInfoFjList();
                    if (guaranteeInfoFjList != null && guaranteeInfoFjList.size() > 0) {
                        for (GuaranteeInfoFj guaranteeInfoFj : guaranteeInfoFjList) {
                            guaranteeInfoFj.setGuaranteeInfoId(guaranteeInfoId);
                            guaranteeInfoFj.setLoanApplicationId(loanApplicationId);
                            guaranteeInfoFj.setLoanApplicationNumber(loanApplicationNumber);
                        }
                        Map<String, List<GuaranteeInfoFj>> typeMap = guaranteeInfoFjList.stream().collect(Collectors.groupingBy(GuaranteeInfoFj::getType));
                        for (String type : typeMap.keySet()) {
                            //每个反担保信息的单个分类的附件集合
                            List<GuaranteeInfoFj> guaranteeInfoFjInsert = typeMap.get(type);
                            String fjName = guaranteeInfoFjInsert.get(0).getName().split("_")[0];
                            List<String> imagePaths = guaranteeInfoFjInsert.stream().filter(e -> type.equals(e.getType()) && ("png".equals(e.getName().split("\\.")[1]) || "jpg".equals(e.getName().split("\\.")[1]) || "jpeg".equals(e.getName().split("\\.")[1]))).map(GuaranteeInfoFj::getUrl).collect(Collectors.toList());
                            //替换前缀，获取服务器上地址
                            if (imagePaths.size() > 0) {
                                for (int i = 0; i < imagePaths.size(); i++) {
                                    ///profile/upload/RZDB202405281147018884551/公司章程_20240528114820A002.png 前缀替换
                                    String replaced = imagePaths.get(i).replace("/profile/upload", RuoYiConfig.getUploadPath());
                                    imagePaths.set(i, replaced);
                                }

                                //先删除原先的所有pdf数据库记录
                                GuaranteeInfoFj gInfoFj = new GuaranteeInfoFj();
                                gInfoFj.setLoanApplicationId(loanApplicationId);
                                gInfoFj.setLoanApplicationNumber(loanApplicationNumber);
                                gInfoFj.setGuaranteeInfoId(guaranteeInfoId);
                                gInfoFj.setRemark("1");
                                List<GuaranteeInfoFj> pdfOne = SpringUtils.getBean(GuaranteeInfoFjMapper.class).selectGuaranteeInfoFjList(gInfoFj);
                                if (pdfOne.size() > 0) {
                                    for (GuaranteeInfoFj guaranteeInfoFj : pdfOne) {
                                        //删除数据库数据附件记录
                                        SpringUtils.getBean(IGuaranteeInfoFjService.class).deleteGuaranteeInfoFjByGuaranteeInfoFjId(guaranteeInfoFj.getGuaranteeInfoFjId());
                                        //删除服务器记录
                                        String urlPdf = guaranteeInfoFj.getUrl();
                                        if (StringUtils.isNotBlank(urlPdf)) {
                                            String filePath = urlPdf.replace("/profile/upload", RuoYiConfig.getUploadPath());
                                            //删除服务器上对应文件
                                            File file = new File(filePath);
                                            if (file.exists()) {
                                                if (file.delete()) {
                                                    System.out.println("删除：" + filePath);
                                                } else {
                                                    System.out.println("删除：" + filePath + "失败");
                                                }
                                            }
                                        }
                                    }
                                }
                                //生成PDF数据库数据
                                createPdfFromImagesGuaranteeInfoFj(list,guaranteeInfoFjInsert, imagePaths, loanApplicationNumber, fjName + "_" + Seq.getId(Seq.uploadSeqType), type, loanApplicationId, guaranteeInfoId);
                            }
                        }
                        //判断是否有反担保GuaranteeInfoFjId
                        List<GuaranteeInfoFj> guaranteeInfoFjListInsert = guaranteeInfoFjList.stream().filter(e -> ObjectUtils.isEmpty(e.getGuaranteeInfoFjId())).collect(Collectors.toList());
                        if (guaranteeInfoFjListInsert.size() > 0) {
                            // 新增反担保附件数据
                            SpringUtils.getBean(GuaranteeInfoFjMapper.class).batchGuaranteeInfoFj(guaranteeInfoFjListInsert);
                        }
                        List<GuaranteeInfoFj> guaranteeInfoFjListUpdate = guaranteeInfoFjList.stream().filter(e -> ObjectUtils.isNotEmpty(e.getGuaranteeInfoFjId())).collect(Collectors.toList());
                        if (guaranteeInfoFjListUpdate.size() > 0) {
                            for (GuaranteeInfoFj guaranteeInfoFj : guaranteeInfoFjListUpdate) {
                                //更新反担保附件信息
                                SpringUtils.getBean(GuaranteeInfoFjMapper.class).updateGuaranteeInfoFj(guaranteeInfoFj);
                            }
                        }
                    }
                }
                //插入附件数据库数据生成的pdf
                if (list.size() > 0){
                    SpringUtils.getBean(IGuaranteeInfoFjService.class).batchGuaranteeInfoFj(list);
                }
                redisCache.deleteObject(key);
            }
        };
    }

    /**
     * @param imagePaths            图片地址集合
     * @param loanApplicationNumber 申请编号
     * @param originalFilename      pdf文件名称
     * @param type                  文件类型
     */
    public static List<GuaranteeInfoFj> createPdfFromImagesGuaranteeInfoFj( List<GuaranteeInfoFj> list ,List<GuaranteeInfoFj> guaranteeInfoFjInsert, List<String> imagePaths, String loanApplicationNumber, String originalFilename, String type, Long loanApplicationId, Long guaranteeInfoId) {
        // 上传文件路径 = 根+申请编号
        String filePath = StringUtils.format("{}/{}/{}.{}", RuoYiConfig.getUploadPath(), loanApplicationNumber,
                FilenameUtils.getBaseName(originalFilename), "pdf");
        //pdf保存位置
        File outPutPdf = new File(filePath);
        try {
            FileUploadUtils.createPdfFromImages(imagePaths, outPutPdf);
            //往附件信息中插入对应PDF数据
            GuaranteeInfoFj guaranteeInfoFj = new GuaranteeInfoFj();
            guaranteeInfoFj.setLoanApplicationId(loanApplicationId);
            guaranteeInfoFj.setLoanApplicationNumber(loanApplicationNumber);
            guaranteeInfoFj.setGuaranteeInfoId(guaranteeInfoId);
            guaranteeInfoFj.setName(originalFilename + ".pdf");
            guaranteeInfoFj.setUrl(StringUtils.format("{}/{}/{}.{}", "/profile/upload", loanApplicationNumber,
                    FilenameUtils.getBaseName(originalFilename), "pdf"));
            guaranteeInfoFj.setType(type);
            //给前端判断是否是系统生成的pdf
            guaranteeInfoFj.setRemark(ONE);
            list.add(guaranteeInfoFj);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }
}

