package com.microservices.file.service.impl;

import com.microservices.common.core.exception.ServiceException;
import com.microservices.file.domain.FileUploadChunk;
import com.microservices.file.domain.FileUploadSession;
import com.microservices.file.mapper.FileUploadChunkMapper;
import com.microservices.file.mapper.FileUploadSessionMapper;
import com.microservices.file.service.IChunkedUploadService;
import com.microservices.file.service.IFileCommonAsyncService;
import com.microservices.file.service.ISysFileInfoService;
import com.microservices.file.utils.CustomExecutorFactory;
import com.microservices.file.utils.Md5Utils;
import com.microservices.system.api.domain.SysFileInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.util.List;

/**
 * 文件Service业务层处理
 *
 * @author otto
 */
@Service
public class FileCommonAsyncServiceImpl implements IFileCommonAsyncService {
    private static final Logger logger = LoggerFactory.getLogger(FileCommonAsyncServiceImpl.class);


    @Autowired
    private FileUploadSessionMapper sessionMapper;

    @Autowired
    private FileUploadChunkMapper chunkMapper;

    @Autowired
    private ISysFileInfoService fileInfoService;

    @Autowired
    @Lazy
    private IChunkedUploadService chunkedUploadService;

    public void executeMergeAsync(String uploadId) {
        CustomExecutorFactory.threadPoolExecutor.execute(() -> {
            FileUploadSession session = null;
            try {
                // 1. 获取会话
                session = sessionMapper.selectByUploadId(uploadId);
                if (session == null) {
                    logger.error("合并任务失败：会话不存在, uploadId={}", uploadId);
                    return;
                }

                // 2. 状态校验
                if (!FileUploadSession.Status.MERGING.getCode().equals(session.getStatus())) {
                    logger.warn("合并任务跳过：状态不是MERGING, uploadId={}, status={}",
                            uploadId, session.getStatus());
                    return;
                }

                // 3. 检查所有分片是否已上传
                int uploadedCount = chunkMapper.countUploadedChunks(uploadId);
                if (uploadedCount < session.getTotalChunks()) {
                    throw new ServiceException("还有分片未上传，无法合并");
                }
                // 4. 哈希校验（SAMPLE类型进行前置哈希校验，FULL类型进行合并后校验）
                validateSampleFileHash( session);

                // 5. 执行合并
                SysFileInfo fileInfo = fileInfoService.uploadChunkedFile(session, session.getUploadType(), session.getHierarchy());


//                // 6. 保存文件
//                MultipartFile mergedMultipartFile = createMultipartFile(
//                        new File(mergedFilePath), session.getFileName());
//                SysFileInfo fileInfo = fileInfoService.upload(
//                        mergedMultipartFile, session.getUploadType(), session.getHierarchy());

                // 7. 更新会话状态
                session.setStatus(FileUploadSession.Status.COMPLETED.getCode());
                session.setFileId(fileInfo.getFileId());
                sessionMapper.updateSession(session);

                // 8. 更新分片状态
                chunkMapper.updateStatusByUploadId(uploadId,
                        FileUploadChunk.Status.MERGED.getCode());

                // 9. 清理临时文件
                cleanupTempFilesAsync(session);

                logger.info("文件合并成功: uploadId={}, fileId={}", uploadId, fileInfo.getFileId());

            } catch (Exception e) {
                logger.error("文件合并失败: uploadId={}", uploadId, e);

                // 更新状态为合并失败
                if (session != null) {
                    session.setStatus(FileUploadSession.Status.MERGE_FAILED.getCode());
                    session.setErrorMessage(e.getMessage());
                    sessionMapper.updateSession(session);
                }
            }
        });

    }

    /**
     * 异步清理临时文件
     */
    private void cleanupTempFilesAsync(FileUploadSession session) {
        new Thread(() -> chunkedUploadService.cleanupTempFiles(session)).start();
    }

    /**
     * 校验文件哈希
     *
     * @param session 上传会话
     * @throws ServiceException 校验失败时抛出异常
     */
    private void validateSampleFileHash(FileUploadSession session) {
        String hashType = session.getHashType();
        String expectedHash = session.getFileSignature();

        if ("SAMPLE".equals(hashType)) {
            List<Integer> sampleChunks = chunkedUploadService.parseSampleChunks(session.getSampleChunks());
            String actualSampleHash = chunkedUploadService.calculateSampleHashFromChunks(
                    session.getTempFilePath(), sampleChunks);
            if (!actualSampleHash.equalsIgnoreCase(expectedHash)) {
                throw new ServiceException("采样点哈希校验失败：期望=" + expectedHash + "，实际=" + actualSampleHash);
            }
        }
    }

    /**
     * 创建MultipartFile对象
     */
    private MultipartFile createMultipartFile(File file, String originalFilename) {
        return new MultipartFile() {
            @Override
            public String getName() {
                return "file";
            }

            @Override
            public String getOriginalFilename() {
                return originalFilename;
            }

            @Override
            public String getContentType() {
                return null;
            }

            @Override
            public boolean isEmpty() {
                return file.length() == 0;
            }

            @Override
            public long getSize() {
                return file.length();
            }

            @Override
            public byte[] getBytes() throws IOException {
                return Files.readAllBytes(file.toPath());
            }

            @Override
            public InputStream getInputStream() throws IOException {
                return new FileInputStream(file);
            }

            @Override
            public void transferTo(File dest) throws IOException, IllegalStateException {
                Files.copy(file.toPath(), dest.toPath());
            }
        };
    }
}
