package com.bcxin.ferry.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.crypto.digest.MD5;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bcxin.ferry.common.CommonConstant;
import com.bcxin.ferry.common.emus.FerryTaskFileStatusEnum;
import com.bcxin.ferry.common.emus.FileTypeEnum;
import com.bcxin.ferry.common.emus.SendBoundaryUrlEnum;
import com.bcxin.ferry.common.utils.Base64Util;
import com.bcxin.ferry.common.utils.DateUtil;
import com.bcxin.ferry.common.utils.FileSpiltMergeUtil;
import com.bcxin.ferry.common.utils.IdGeneratorSnowflake;
import com.bcxin.ferry.configs.BoundaryServerConfig;
import com.bcxin.ferry.dao.mapper.FerryTaskFileMapper;
import com.bcxin.ferry.dao.mapper.FerryTaskMapper;
import com.bcxin.ferry.dtos.FerryFileDto;
import com.bcxin.ferry.dtos.response.boundary.BoundaryResult;
import com.bcxin.ferry.entity.FerryTaskEntity;
import com.bcxin.ferry.entity.FerryTaskFileEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * 摆渡任务文件表(ferry_task_file)服务实现类
 *
 * @author : linchunpeng
 * @date : 2024-3-6
 */
@Slf4j
@Service
public class FerryTaskFileService extends ServiceImpl<FerryTaskFileMapper, FerryTaskFileEntity> {

    @Autowired
    private SendRequestToBoundaryService sendRequestToBoundaryService;
    @Autowired
    private FerryTaskMapper ferryTaskMapper;
    @Autowired
    private BoundaryServerConfig boundaryServerConfig;
    @Autowired
    private IdGeneratorSnowflake snowflake;

    private final static String NORMAL_FILE_SUFFIX = "DOC,DOCX,XLS,XLSX,CSV,PPT,PPTX,PDF,PNG,JPG,GIF";

    /**
     * description：根据摆渡任务id，查询文件列表
     * author：linchunpeng
     * date：2024/3/12
     */
    public List<FerryTaskFileEntity> queryByTaskId(Long taskId) {
        LambdaQueryChainWrapper<FerryTaskFileEntity> lqw = this.lambdaQuery();
        lqw.eq(FerryTaskFileEntity::getTaskId, taskId);
        lqw.orderByAsc(FerryTaskFileEntity::getCreateTime);
        return lqw.list();
    }

    /**
     * description：根据摆渡任务id，查询任务文件
     * author：linchunpeng
     * date：2024/3/12
     */
    public FerryTaskFileEntity queryTaskFileByTaskId(Long taskId) {
        LambdaQueryChainWrapper<FerryTaskFileEntity> lqw = this.lambdaQuery();
        lqw.eq(FerryTaskFileEntity::getTaskId, taskId);
        lqw.eq(FerryTaskFileEntity::getFileType, FileTypeEnum.TASK.getCode());
        lqw.orderByDesc(FerryTaskFileEntity::getCreateTime);
        lqw.last("limit 1");
        List<FerryTaskFileEntity> list = lqw.list();
        return CollectionUtil.isNotEmpty(list) ? list.get(0) : null;
    }

    /**
     * description：根据摆渡任务id，查询明细文件列表（不含任务文件）
     * author：linchunpeng
     * date：2024/3/12
     */
    public List<FerryTaskFileEntity> queryDetailFileByTaskId(Long taskId) {
        LambdaQueryChainWrapper<FerryTaskFileEntity> lqw = this.lambdaQuery();
        lqw.eq(FerryTaskFileEntity::getTaskId, taskId);
        lqw.ne(FerryTaskFileEntity::getFileType, FileTypeEnum.TASK.getCode());
        lqw.orderByAsc(FerryTaskFileEntity::getCreateTime);
        return lqw.list();
    }

    /**
     * description：查询未摆渡完成或失败的文件数；
     * author：linchunpeng
     * date：2024/3/13
     */
    public long countNullFerryResultByTaskId(Long taskId) {
        LambdaQueryChainWrapper<FerryTaskFileEntity> lqw = this.lambdaQuery();
        lqw.eq(FerryTaskFileEntity::getTaskId, taskId);
        lqw.eq(FerryTaskFileEntity::getIsSplit, 0);
        lqw.in(FerryTaskFileEntity::getFileStatus, 1, 2);
        return lqw.count();
    }

    /**
     * description：创建摆渡任务文件
     * author：linchunpeng
     * date：2024/3/12
     */
    @Transactional
    public void createFerryTaskFile(FerryTaskEntity ferryTaskEntity, File file) {
        log.info("初始化文件：{}", file.getAbsolutePath());
        String fileName = file.getName();
        FerryTaskFileEntity fileEntity = new FerryTaskFileEntity();
        fileEntity.setId(snowflake.snowflakeId());
        fileEntity.setTaskId(ferryTaskEntity.getId());
        fileEntity.setFileName(fileName);
        //取出后缀名
        String suffix = fileName.substring(fileName.lastIndexOf(".")+1).toUpperCase(Locale.ROOT);
        if (fileName.startsWith(CommonConstant.FERRY_TASK_FILE_PREFIX)) {
            //任务文件
            fileEntity.setFileType(FileTypeEnum.TASK.getCode());
        } else if (suffix.equals("SQL")) {
            //sql脚本
            fileEntity.setFileType(FileTypeEnum.SQL.getCode());
        } else if (suffix.equals("TXT")) {
            //txt文件
            fileEntity.setFileType(FileTypeEnum.TXT.getCode());
        } else if (this.checkSpecial(fileName, suffix, file.length())) {
            //特殊字符文件名
            fileEntity.setFileType(FileTypeEnum.SPECIAL.getCode());
        } else {
            //普通文件
            fileEntity.setFileType(FileTypeEnum.NORMAL.getCode());
        }
        //文件存放位置，从摆渡包名开始
        String absolutePath = file.getAbsolutePath();
        absolutePath = absolutePath.replaceAll("\\\\", "/");
        absolutePath = absolutePath.substring(absolutePath.indexOf("/".concat(ferryTaskEntity.getRequestId())));
        fileEntity.setFileUrl(absolutePath);

        fileEntity.setFileStatus(FerryTaskFileStatusEnum.PULL_COMPLETE.getCode());
        fileEntity.setFileSize(new BigDecimal(file.length()).divide(new BigDecimal(1024), 2, RoundingMode.HALF_UP));
        if (file.length() > boundaryServerConfig.getMaxFileSize()) {
            log.info("文件：{}，需要拆分", file.getAbsolutePath());
            //文件超限，需要拆分
            fileEntity.setIsSplit(1);
            fileEntity.setSplitFileIds(this.createChildrenFileList(ferryTaskEntity,
                    FileSpiltMergeUtil.splitFile(boundaryServerConfig.getMaxFileSize() * 3, file)));
            log.info("拆分出的文件id为：{}", fileEntity.getSplitFileIds());
        } else {
            log.info("文件：{}，不需要拆分", file.getAbsolutePath());
            fileEntity.setIsSplit(0);
        }
        if (!fileName.startsWith(CommonConstant.FERRY_TASK_FILE_PREFIX)) {
            //不是任务文件
            fileEntity.setFileMd5(MD5.create().digestHex16(file));
        }
        fileEntity.setCreateTime(new Date());
        fileEntity.setUpdateTime(new Date());
        this.save(fileEntity);
        log.info("初始化完成，文件：{}", file.getAbsolutePath());
    }

    /**
     * description：是否包含特殊文件
     * author：linchunpeng
     * date：2024/9/14
     */
    private boolean checkSpecial(String fileName, String suffix, long fileLength) {
        if (fileLength < 1024) {
            //小于1k的，定义为特殊文件
            return true;
        }
        if (!NORMAL_FILE_SUFFIX.contains(suffix)) {
            //不是在正常文件范围内的，定义为特殊文件
            return true;
        }
        if (fileName.matches(".*[\u4e00-\u9fa5]+.*")) {
            //文件名称包含中文
            return true;
        }
        // 正则表达式规则，
        String regex = ".*[[ `~!@#$%^&*+=|{}':;',\\[\\]<>/?~！@#￥%……&*（）——+|{}【】‘；：”“'。，、？]|\\n|\\r|\\t].*";
        return fileName.matches(regex);
    }

    /**
     * description：创建子文件数据库记录
     * author：linchunpeng
     * date：2024/3/12
     */
    private String createChildrenFileList(FerryTaskEntity ferryTaskEntity, List<String> childrenFilePathList) {
        StringBuffer splitFileIds = new StringBuffer();
        if (CollectionUtil.isNotEmpty(childrenFilePathList)) {
            for (String path : childrenFilePathList) {
                File file = new File(path);
                String fileName = file.getName();
                FerryTaskFileEntity fileEntity = new FerryTaskFileEntity();
                fileEntity.setId(snowflake.snowflakeId());
                fileEntity.setTaskId(ferryTaskEntity.getId());
                fileEntity.setFileName(fileName);
                fileEntity.setFileType(FileTypeEnum.CHILDREN.getCode());
                //文件存放位置，从摆渡包名开始
                String absolutePath = file.getAbsolutePath();
                absolutePath = absolutePath.replaceAll("\\\\", "/");
                absolutePath = absolutePath.substring(absolutePath.indexOf("/".concat(ferryTaskEntity.getRequestId())));
                fileEntity.setFileUrl(absolutePath);

                fileEntity.setFileStatus(FerryTaskFileStatusEnum.PULL_COMPLETE.getCode());
                fileEntity.setFileSize(new BigDecimal(file.length()).divide(new BigDecimal(1024), 2, RoundingMode.HALF_UP));
                fileEntity.setIsSplit(0);
                fileEntity.setFileMd5(MD5.create().digestHex16(file));
                fileEntity.setCreateTime(new Date());
                fileEntity.setUpdateTime(new Date());
                this.save(fileEntity);
                splitFileIds.append(fileEntity.getId().toString()).append(",");
            }
        }
        if (splitFileIds.length() == 0) {
            return null;
        }
        return splitFileIds.substring(0, splitFileIds.length() -1);
    }


    /**
     * description：摆渡任务信息文件
     * author：linchunpeng
     * date：2024/3/13
     */
    @Transactional
    public void ferryTaskFile(Long taskId) {
        FerryTaskFileEntity taskFileEntity = this.queryTaskFileByTaskId(taskId);
        this.ferryFileToBoundary(taskFileEntity, SendBoundaryUrlEnum.SEND_TASK_FILE);
    }


    /**
     * description：单个文件摆渡
     * author：linchunpeng
     * date：2024/3/13
     */
    @Transactional
    public void ferryFileToBoundary(FerryTaskFileEntity taskFileEntity, SendBoundaryUrlEnum urlEnum) {
        FerryTaskEntity ferryTaskEntity = ferryTaskMapper.selectById(taskFileEntity.getTaskId());
        FerryFileDto ferryFileDto = new FerryFileDto();
        ferryFileDto.setFerryTaskId(taskFileEntity.getTaskId().toString());
        ferryFileDto.setRequestId(ferryTaskEntity.getRequestId());
        ferryFileDto.setFerry_accept_url(urlEnum.getValue());
        ferryFileDto.setFileType(taskFileEntity.getFileType());
        ferryFileDto.setFileId(taskFileEntity.getId().toString());

        if (urlEnum.getCode() == SendBoundaryUrlEnum.SEND_TASK_FILE.getCode()) {
            //如果是任务文件，需要增加参数，是否摆渡到政务外网
            if (ferryTaskEntity.getRegionCode().equals("govin-to-govout")) {
                ferryFileDto.setIsPushZw(1);
            } else {
                ferryFileDto.setIsPushZw(0);
            }
        }

        //转成map
        Map<String, Object> paramMap = BeanUtil.beanToMap(ferryFileDto);
        File file = new File(ferryTaskEntity.getPackageUrl().concat(taskFileEntity.getFileUrl()));
        if (taskFileEntity.getIsSplit() == 0 && file.length() != 0) {
            String fileToBase64 = Base64Util.fileToBase64(file, taskFileEntity.getFileType() != FileTypeEnum.NORMAL.getCode());
            if (taskFileEntity.getFileType() == FileTypeEnum.NORMAL.getCode()) {
                //普通文件，放img_base64字段
                paramMap.put("img_base64", fileToBase64);
            } else {
                //其他字段，放拓展字段
                List<String> fileBase64List = this.splitStringByLength(fileToBase64, 1000);
                paramMap.put("paramContentSize", fileBase64List.size());
                for (int i = 0; i < fileBase64List.size(); i++) {
                    paramMap.put("paramContent_" + i, fileBase64List.get(i));
                }
            }
        }

        BoundaryResult boundaryResult = sendRequestToBoundaryService.send(paramMap);
        if (boundaryResult != null && "0".equals(boundaryResult.getStatus_code())) {
            taskFileEntity.setBoundaryTaskId(boundaryResult.getData().get(0).getTask_id());
            taskFileEntity.setFileStatus(FerryTaskFileStatusEnum.FERRY_BEGIN.getCode());
        } else {
            taskFileEntity.setFileStatus(FerryTaskFileStatusEnum.FERRY_FAIL.getCode());
            taskFileEntity.setFerryResult(boundaryResult != null ? boundaryResult.getMsg() : "接口调用失败");
        }
        taskFileEntity.setRetryCount(taskFileEntity.getRetryCount() == null ? 0 : taskFileEntity.getRetryCount() + 1);
        this.updateById(taskFileEntity);
    }

    private List<String> splitStringByLength(String input, int length) {
        List<String> result = new ArrayList<>();
        int start = 0;
        while (start < input.length()) {
            int end = Math.min(start + length, input.length());
            result.add(input.substring(start, end));
            start += length;
        }
        return result;
    }

    /**
     * description：查询大于半小时小时还未摆渡完成的文件
     * author：linchunpeng
     * date：2024/3/20
     */
    public List<FerryTaskFileEntity> queryHalfHourNotCompleteList() {
        //大于半小时小时还未摆渡完成的文件
        Date intervalTime = DateUtil.getBeforeNumMinuteTime(new Date(), 30);

        LambdaQueryChainWrapper<FerryTaskFileEntity> lqw = this.lambdaQuery();
        lqw.ne(FerryTaskFileEntity::getFileStatus, FerryTaskFileStatusEnum.FERRY_COMPLETE.getCode());
        lqw.ne(FerryTaskFileEntity::getFileType, FileTypeEnum.TASK.getCode());
        lqw.lt(FerryTaskFileEntity::getRetryCount, 10);
        lqw.lt(FerryTaskFileEntity::getCreateTime, intervalTime);
        lqw.orderByAsc(FerryTaskFileEntity::getCreateTime);
        return lqw.list();
    }

}