package cn.meowrain.aioj.backend.fileservice.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.meowrain.aioj.backend.fileservice.dao.entity.AttachmentDO;
import cn.meowrain.aioj.backend.fileservice.dao.mapper.AttachmentMapper;
import cn.meowrain.aioj.backend.fileservice.dto.resp.HashCheckRespDTO;
import cn.meowrain.aioj.backend.fileservice.service.AttachmentService;
import cn.meowrain.aioj.backend.fileservice.storage.FileStorageStrategy;
import cn.meowrain.aioj.backend.framework.core.enums.DelStatusEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;

/**
 * <p>
 * 通用附件表 服务实现类
 * </p>
 *
 * @author meowrain
 * @since 2026-01-10
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AttachmentServiceImpl extends ServiceImpl<AttachmentMapper, AttachmentDO> implements AttachmentService {

    private final FileStorageStrategy fileStorageStrategy;

    @Override
    public AttachmentDO upload(MultipartFile file, String hash) {
        try {
            String originalFilename = file.getOriginalFilename();
            String fileExtension = FileUtil.extName(originalFilename);

            // 如果传入了hash，先检查是否已存在（秒传）
            if (StrUtil.isNotBlank(hash)) {
                AttachmentDO existingFile = getOne(new LambdaQueryWrapper<AttachmentDO>()
                        .eq(AttachmentDO::getFileHash, hash)
                        .eq(AttachmentDO::getIsDeleted, DelStatusEnum.STATUS_NORMAL.code())
                        .last("LIMIT 1"));

                if (existingFile != null) {
                    log.info("文件已存在，返回已有文件: fileName={}, hash={}, existingId={}",
                            originalFilename, hash, existingFile.getId());
                    return existingFile;
                }
            }

            // 文件不存在，上传并保存
            return uploadAndSave(file, originalFilename, fileExtension, hash);

        } catch (IOException e) {
            log.error("文件上传失败: {}", file.getOriginalFilename(), e);
            throw new RuntimeException("文件上传失败: " + e.getMessage(), e);
        }
    }

    /**
     * 上传文件并保存记录
     */
    private AttachmentDO uploadAndSave(MultipartFile file, String originalFilename,
                                        String fileExtension, String fileHash) throws IOException {
        String fileName = IdUtil.fastSimpleUUID() + StrUtil.DOT + fileExtension;
        String datePath = LocalDateTime.now().toLocalDate().toString().replace("-", "/");
        String relativePath = datePath + "/" + fileName;

        fileStorageStrategy.upload(file, relativePath);

        AttachmentDO attachmentDO = new AttachmentDO();
        attachmentDO.setId(IdUtil.getSnowflakeNextId());
        attachmentDO.setFileName(originalFilename);
        attachmentDO.setFileExtension(fileExtension);
        attachmentDO.setFileSize(file.getSize());
        attachmentDO.setFileHash(fileHash);
        attachmentDO.setMimeType(file.getContentType());
        attachmentDO.setStorageType(fileStorageStrategy.getStorageType());
        attachmentDO.setStoragePath(relativePath);
        attachmentDO.setCreatedAt(LocalDateTime.now());
        attachmentDO.setUpdatedAt(LocalDateTime.now());
        attachmentDO.setIsDeleted(DelStatusEnum.STATUS_NORMAL.code());

        save(attachmentDO);
        log.info("文件上传成功: fileName={}, storageType={}, storagePath={}, fileHash={}, size={}KB",
                originalFilename, fileStorageStrategy.getStorageType(), relativePath,
                fileHash, file.getSize() / 1024);

        return attachmentDO;
    }

    @Override
    public HashCheckRespDTO checkHash(String hash) {
        HashCheckRespDTO respDTO = new HashCheckRespDTO();
        respDTO.setExists(false);

        if (StrUtil.isBlank(hash)) {
            return respDTO;
        }

        AttachmentDO existingFile = getOne(new LambdaQueryWrapper<AttachmentDO>()
                .eq(AttachmentDO::getFileHash, hash)
                .eq(AttachmentDO::getIsDeleted, DelStatusEnum.STATUS_NORMAL.code())
                .last("LIMIT 1"));

        if (existingFile != null) {
            respDTO.setExists(true);
            respDTO.setFileId(existingFile.getId());
            respDTO.setUrl(fileStorageStrategy.getFileUrl(existingFile.getStoragePath()));
            log.info("文件哈希已存在，支持秒传: hash={}, fileId={}", hash, existingFile.getId());
        }

        return respDTO;
    }
}
