package org.xyzh.file.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.xyzh.api.file.FileService;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.dto.system.TbSysFile;
import org.xyzh.common.utils.IDUtils;
import org.xyzh.file.mapper.FileMapper;
import org.xyzh.file.strategy.FileStorageStrategy;
import org.xyzh.file.strategy.FileStorageStrategyFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @description 文件服务实现
 * @filename FileServiceImpl.java
 * @author yslg
 * @copyright xyzh
 * @since 2025-10-16
 */
@Slf4j
@Service
public class FileServiceImpl implements FileService {

    @Autowired
    private FileMapper fileMapper;

    @Autowired
    private FileStorageStrategyFactory strategyFactory;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbSysFile> uploadFile(MultipartFile file, String module, String businessId) {
        return uploadFile(file, module, businessId, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbSysFile> uploadFile(MultipartFile file, String module, String businessId, String uploader) {
        ResultDomain<TbSysFile> resultDomain = new ResultDomain<>();
        
        try {
            if (file == null || file.isEmpty()) {
                resultDomain.fail("文件不能为空");
                return resultDomain;
            }

            // 获取存储策略
            FileStorageStrategy strategy = strategyFactory.getDefaultStrategy();

            // 生成文件名
            String originalFileName = file.getOriginalFilename();
            String fileExtension = "";
            if (originalFileName != null && originalFileName.contains(".")) {
                fileExtension = originalFileName.substring(originalFileName.lastIndexOf("."));
            }
            String fileName = UUID.randomUUID().toString().replace("-", "") + fileExtension;

            // 上传文件
            String filePath = strategy.upload(file, fileName, module);

            // 保存文件记录
            TbSysFile sysFile = new TbSysFile();
            String fileId = IDUtils.generateID();
            sysFile.setID(fileId);
            sysFile.setFileID(fileId);
            sysFile.setFileName(fileName);
            sysFile.setOriginalName(originalFileName);
            sysFile.setFilePath(filePath);
            sysFile.setFileUrl(strategy.getFileUrl(filePath));
            sysFile.setFileSize(file.getSize());
            sysFile.setMimeType(file.getContentType());
            sysFile.setStorageType(strategy.getStorageType());
            sysFile.setModule(module);
            sysFile.setBusinessID(businessId);
            sysFile.setUploader(uploader);
            sysFile.setCreateTime(new Date());
            sysFile.setUpdateTime(new Date());
            sysFile.setDeleted(false);

            // 判断文件类型
            String mimeType = file.getContentType();
            if (mimeType != null) {
                if (mimeType.startsWith("image/")) {
                    sysFile.setFileType("image");
                } else if (mimeType.startsWith("video/")) {
                    sysFile.setFileType("video");
                } else if (mimeType.startsWith("audio/")) {
                    sysFile.setFileType("audio");
                } else if (mimeType.contains("pdf")) {
                    sysFile.setFileType("pdf");
                } else if (mimeType.contains("word") || mimeType.contains("document")) {
                    sysFile.setFileType("document");
                } else if (mimeType.contains("excel") || mimeType.contains("spreadsheet")) {
                    sysFile.setFileType("excel");
                } else {
                    sysFile.setFileType("other");
                }
            }

            fileMapper.insertFile(sysFile);

            log.info("文件上传成功: fileId={}, fileName={}, storageType={}", 
                    sysFile.getID(), fileName, strategy.getStorageType());

            resultDomain.success("文件上传成功", sysFile);
            return resultDomain;
        } catch (Exception e) {
            log.error("文件上传失败", e);
            resultDomain.fail("文件上传失败: " + e.getMessage());
            return resultDomain;
        }
    }

    @Override
    public ResultDomain<byte[]> downloadFile(String fileId) {
        ResultDomain<byte[]> resultDomain = new ResultDomain<>();
        
        try {
            TbSysFile sysFile = fileMapper.selectFileById(fileId);
            if (sysFile == null || sysFile.getDeleted()) {
                resultDomain.fail("文件不存在或已被删除");
                return resultDomain;
            }

            // 获取存储策略
            FileStorageStrategy strategy = strategyFactory.getStrategy(sysFile.getStorageType());

            // 下载文件
            byte[] fileData = strategy.download(sysFile.getFilePath());

            log.info("文件下载成功: fileId={}, fileName={}", fileId, sysFile.getFileName());

            resultDomain.success("文件下载成功", fileData);
            return resultDomain;
        } catch (Exception e) {
            log.error("文件下载失败: fileId={}", fileId, e);
            resultDomain.fail("文件下载失败: " + e.getMessage());
            return resultDomain;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbSysFile> deleteFile(String fileId) {
        ResultDomain<TbSysFile> resultDomain = new ResultDomain<>();
        
        try {
            TbSysFile sysFile = fileMapper.selectFileById(fileId);
            if (sysFile == null) {
                resultDomain.fail("文件不存在");
                return resultDomain;
            }

            if (sysFile.getDeleted()) {
                resultDomain.fail("文件已被删除");
                return resultDomain;
            }

            // 逻辑删除
            int result = fileMapper.logicDeleteFileById(fileId);
            if (result > 0) {
                log.info("文件逻辑删除成功: fileId={}", fileId);
                resultDomain.success("文件删除成功", sysFile);
                return resultDomain;
            } else {
                resultDomain.fail("文件删除失败");
                return resultDomain;
            }
        } catch (Exception e) {
            log.error("文件删除失败: fileId={}", fileId, e);
            resultDomain.fail("文件删除失败: " + e.getMessage());
            return resultDomain;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbSysFile> deleteFilePhysically(String fileId) {
        ResultDomain<TbSysFile> resultDomain = new ResultDomain<>();
        
        try {
            TbSysFile sysFile = fileMapper.selectFileByIdIncludeDeleted(fileId);
            if (sysFile == null) {
                resultDomain.fail("文件不存在");
                return resultDomain;
            }

            // 获取存储策略
            FileStorageStrategy strategy = strategyFactory.getStrategy(sysFile.getStorageType());

            // 删除物理文件
            boolean deleted = strategy.delete(sysFile.getFilePath());
            if (!deleted) {
                log.warn("物理文件删除失败，可能文件不存在: filePath={}", sysFile.getFilePath());
            }

            // 删除数据库记录
            fileMapper.deleteFileById(fileId);

            log.info("文件物理删除成功: fileId={}", fileId);

            resultDomain.success("文件物理删除成功", sysFile);
            return resultDomain;
        } catch (Exception e) {
            log.error("文件物理删除失败: fileId={}", fileId, e);
            resultDomain.fail("文件物理删除失败: " + e.getMessage());
            return resultDomain;
        }
    }

    @Override
    public ResultDomain<TbSysFile> getFileById(String fileId) {
        ResultDomain<TbSysFile> resultDomain = new ResultDomain<>();
        
        try {
            TbSysFile sysFile = fileMapper.selectFileById(fileId);
            if (sysFile == null || sysFile.getDeleted()) {
                resultDomain.fail("文件不存在或已被删除");
                return resultDomain;
            }
            resultDomain.success("查询成功", sysFile);
            return resultDomain;
        } catch (Exception e) {
            log.error("查询文件失败: fileId={}", fileId, e);
            resultDomain.fail("查询文件失败: " + e.getMessage());
            return resultDomain;
        }
    }

    @Override
    public ResultDomain<TbSysFile> getFilesByBusinessId(String module, String businessId) {
        ResultDomain<TbSysFile> resultDomain = new ResultDomain<>();
        
        try {
            List<TbSysFile> files = fileMapper.selectFilesByBusinessId(module, businessId);
            resultDomain.success("查询成功", files);
            return resultDomain;
        } catch (Exception e) {
            log.error("查询业务文件列表失败: module={}, businessId={}", module, businessId, e);
            resultDomain.fail("查询文件列表失败: " + e.getMessage());
            return resultDomain;
        }
    }

    @Override
    public ResultDomain<TbSysFile> getFilesByUploader(String uploader) {
        ResultDomain<TbSysFile> resultDomain = new ResultDomain<>();
        
        try {
            List<TbSysFile> files = fileMapper.selectFilesByUploader(uploader);
            resultDomain.success("查询成功", files);
            return resultDomain;
        } catch (Exception e) {
            log.error("查询用户文件列表失败: uploader={}", uploader, e);
            resultDomain.fail("查询文件列表失败: " + e.getMessage());
            return resultDomain;
        }
    }

    @Override
    public ResultDomain<String> getFileUrl(String fileId) {
        ResultDomain<String> resultDomain = new ResultDomain<>();
        
        try {
            TbSysFile sysFile = fileMapper.selectFileById(fileId);
            if (sysFile == null || sysFile.getDeleted()) {
                resultDomain.fail("文件不存在或已被删除");
                return resultDomain;
            }

            // 如果数据库中已有URL且不是MinIO类型（MinIO的URL有时效性），直接返回
            if (sysFile.getFileUrl() != null && !"minio".equals(sysFile.getStorageType())) {
                resultDomain.success("获取成功", sysFile.getFileUrl());
                return resultDomain;
            }

            // 重新生成URL
            FileStorageStrategy strategy = strategyFactory.getStrategy(sysFile.getStorageType());
            String url = strategy.getFileUrl(sysFile.getFilePath());

            resultDomain.success("获取成功", url);
            return resultDomain;
        } catch (Exception e) {
            log.error("获取文件URL失败: fileId={}", fileId, e);
            resultDomain.fail("获取文件URL失败: " + e.getMessage());
            return resultDomain;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbSysFile> batchUploadFiles(MultipartFile[] files, String module, String businessId, String uploader) {
        ResultDomain<TbSysFile> resultDomain = new ResultDomain<>();
        
        try {
            if (files == null || files.length == 0) {
                resultDomain.fail("文件列表不能为空");
                return resultDomain;
            }

            List<TbSysFile> uploadedFiles = new ArrayList<>();
            List<String> errorMessages = new ArrayList<>();

            for (int i = 0; i < files.length; i++) {
                MultipartFile file = files[i];
                try {
                    ResultDomain<TbSysFile> uploadResult = uploadFile(file, module, businessId, uploader);
                    if (uploadResult.isSuccess() && uploadResult.getData() != null) {
                        uploadedFiles.add((TbSysFile) uploadResult.getData());
                    } else {
                        errorMessages.add(String.format("文件%d上传失败: %s", i + 1, uploadResult.getMessage()));
                    }
                } catch (Exception e) {
                    log.error("批量上传文件时出错: index={}, fileName={}", i, file.getOriginalFilename(), e);
                    errorMessages.add(String.format("文件%d(%s)上传失败: %s", i + 1, file.getOriginalFilename(), e.getMessage()));
                }
            }

            if (uploadedFiles.isEmpty()) {
                resultDomain.fail("所有文件上传失败: " + String.join("; ", errorMessages));
                return resultDomain;
            }

            if (!errorMessages.isEmpty()) {
                log.warn("批量上传部分失败: 成功={}, 失败={}", uploadedFiles.size(), errorMessages.size());
                resultDomain.success(String.format("批量上传完成: 成功%d个，失败%d个。失败信息: %s", 
                        uploadedFiles.size(), errorMessages.size(), String.join("; ", errorMessages)), uploadedFiles);
            } else {
                log.info("批量上传全部成功: count={}", uploadedFiles.size());
                resultDomain.success(String.format("批量上传成功: 共%d个文件", uploadedFiles.size()), uploadedFiles);
            }

            return resultDomain;
        } catch (Exception e) {
            log.error("批量上传文件失败", e);
            resultDomain.fail("批量上传文件失败: " + e.getMessage());
            return resultDomain;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbSysFile> batchDeleteFiles(String[] fileIds) {
        ResultDomain<TbSysFile> resultDomain = new ResultDomain<>();
        
        try {
            if (fileIds == null || fileIds.length == 0) {
                resultDomain.fail("文件ID列表不能为空");
                return resultDomain;
            }

            List<String> fileIdList = Arrays.asList(fileIds);
            int result = fileMapper.batchLogicDeleteFiles(fileIdList);

            log.info("批量逻辑删除文件成功: count={}", result);

            resultDomain.success("批量删除成功", new ArrayList<TbSysFile>());
            return resultDomain;
        } catch (Exception e) {
            log.error("批量删除文件失败", e);
            resultDomain.fail("批量删除文件失败: " + e.getMessage());
            return resultDomain;
        }
    }
}

