package com.jwipc.job.logic.impl;

import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.jwipc.exception.DaoException;
import com.jwipc.job.logic.FileLogic;
import com.jwipc.sys.entity.Attachment;
import com.jwipc.sys.service.IAttachmentService;
import com.jwipc.util.DateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.util.Date;

import static com.baomidou.mybatisplus.core.toolkit.StringPool.DASH;

/**
 * <p>
 *  文件处理-实现类
 * </p>
 *
 * @author Chen Tianshi
 * @since 2025/9/12 17:23
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class FileLogicImpl implements FileLogic {
    @Value("${sys.file-path}")
    private String SYSTEM_FILE_PATH;

    private final IAttachmentService attachmentService;

    @Override
    public Attachment uploadFile(File file) {
        if (file == null || !file.exists() || file.length() == 0) {
            throw new DaoException("文件不存在或为空");
        }
        final String hash = hash(file);
        try {
            final String originalFilename = file.getName();
            // 生成日期路径
            Pair<String, String> pathPair = genDatePath();
            final String absoluteDirPath = pathPair.getKey();
            final String datePath = pathPair.getValue();
            // 需要重新生成文件名
            final String fileSuffix = FileUtil.getSuffix(originalFilename);
            final String fileName = StrUtil.concat(false, UUID.randomUUID().toString(), StrUtil.DOT, fileSuffix);
            // 构建完整目标路径
            final String absoluteFilePath = StrUtil.concat(false, absoluteDirPath, File.separator, fileName);
            final File targetFile = new File(absoluteFilePath);
            // 创建父级目录
            Path parentDir = targetFile.toPath().getParent();
            Files.createDirectories(parentDir);
            // 复制文件
            Files.copy(file.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            // 需要保存文件到数据库
            Attachment attachment = new Attachment();
            attachment.setFileSize(file.length());
            attachment.setFileName(originalFilename);
            attachment.setFileType(FileTypeUtil.getType(targetFile));
            attachment.setHash(hash);
            // 这个地方是相对路径需要把
            attachment.setFilePath(StrUtil.concat(false, datePath, File.separator, fileName));
            attachment.setCreateUser(1L);
            attachment.setDateline(LocalDateTime.now());
            attachmentService.save(attachment);
            return attachment;
        } catch (IOException e) {
            log.error("文件上传失败：{}", file.getName(), e);
            throw new DaoException("文件上传失败");
        }
    }

    @Override
    public void safeDeleteTemplate(File file) {
        if (file == null) return;

        try {
            // 使用NIO API删除更可靠
            Files.deleteIfExists(file.toPath());
        } catch (IOException e) {
            log.warn("删除临时文件失败，尝试标记删除: {}", file.getAbsolutePath());
            file.deleteOnExit(); // JVM退出时删除
        }
    }

    private String hash(File file) {
        if (file == null || file.length() == 0) {
            return StringUtils.EMPTY;
        }
        try (FileInputStream fis = new FileInputStream(file)) {
            return DigestUtils.md5Hex(fis);
        } catch (IOException e) {
            log.error("计算文件hash失败: {}", file.getName(), e);
            return StringUtils.EMPTY;
        }
    }

    private Pair<String, String> genDatePath() {
        final String yyyyMMdd = DateUtils.formatYYYYMMDDDash(new Date());
        final String datePath = StringUtils.replace(yyyyMMdd, DASH, File.separator);
        return Pair.of(getFilePath() + datePath, datePath);
    }

    private String getFilePath() {
        if (SYSTEM_FILE_PATH.endsWith(File.separator)) {
            return SYSTEM_FILE_PATH;
        } else {
            return SYSTEM_FILE_PATH + File.separator;
        }
    }
}
