package com.aegis.file.service.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.aegis.common.config.RuoYiConfig;
import com.aegis.common.core.domain.entity.SysUser;
import com.aegis.common.exception.ServiceException;
import com.aegis.common.utils.SecurityUtils;
import com.aegis.common.utils.file.FileUtils;
import com.aegis.common.utils.file.FileUploadUtils;
import com.aegis.file.domain.FileInfo;
import com.aegis.file.enums.FileStatus;
import com.aegis.file.enums.FileCategory;
import com.aegis.file.mapper.FileMapper;
import com.aegis.file.service.IFileService;
import com.aegis.file.utils.FileCategoryUtils;
import com.aegis.system.service.ISysUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 文件服务实现类
 * 
 * @author aegis
 */
@Service
public class FileServiceImpl implements IFileService {
    
    private static final Logger log = LoggerFactory.getLogger(FileServiceImpl.class);
    
    @Autowired
    private FileMapper fileMapper;
    
    @Autowired
    private ISysUserService userService;
    
    @Override
    @Transactional
    public FileInfo uploadFile(MultipartFile file) {
        String originalFilename = null;
        try {
            // 0. 参数校验
            if (file == null || file.isEmpty()) {
                throw new ServiceException("上传文件不能为空");
            }
            originalFilename = file.getOriginalFilename();
            if (originalFilename == null || originalFilename.trim().isEmpty()) {
                throw new ServiceException("文件名不能为空");
            }
            
            // 1. 使用现有工具类上传文件
            String uploadPath = RuoYiConfig.getUploadPath();
            String fileName = FileUploadUtils.upload(uploadPath, file);
            
            // 2. 构建文件信息对象
            FileInfo fileInfo = new FileInfo();
            // file_path存储相对路径（如：/profile/upload/2025/11/05/test_123456.pdf）
            fileInfo.setFilePath(fileName);
            fileInfo.setOriginalName(originalFilename);
            fileInfo.setFileSize(file.getSize());
            fileInfo.setFileType(FileUploadUtils.getExtension(file));
            fileInfo.setMimeType(file.getContentType());
            
            // 3. 自动推断文件分类（使用枚举）
            FileCategory category = FileCategoryUtils.inferFileCategory(fileInfo.getFileType());
            fileInfo.setFileCategory(category.getCode());
            
            // 4. 设置文件状态（使用枚举）
            fileInfo.setStatus(FileStatus.NORMAL.getCode());
            fileInfo.setDownloadCount(0);
            
            // 5. 设置上传者信息
            Long userId = SecurityUtils.getUserId();
            SysUser user = userService.selectUserById(userId);
            if (user != null) {
                fileInfo.setUploadUserId(userId);
                fileInfo.setUploadUserName(user.getUserName());
            }
            
            fileInfo.setCreateBy(SecurityUtils.getUsername());
            
            // 6. 保存文件信息到数据库
            fileMapper.insertFileInfo(fileInfo);
            
            log.info("文件上传成功，fileId: {}, originalName: {}, fileSize: {}", 
                    fileInfo.getId(), originalFilename, file.getSize());
            return fileInfo;
        } catch (ServiceException e) {
            // ServiceException直接抛出
            throw e;
        } catch (Exception e) {
            log.error("文件上传失败，originalName: {}", originalFilename, e);
            throw new ServiceException("文件上传失败：" + e.getMessage());
        }
    }
    
    @Override
    public FileInfo selectFileById(Long fileId) {
        if (fileId == null) {
            return null;
        }
        FileInfo fileInfo = fileMapper.selectFileInfoById(fileId);
        // Mapper已经过滤了del_flag='0'，如果返回null说明文件不存在或已删除
        return fileInfo;
    }
    
    @Override
    public List<FileInfo> selectFilesByIds(Long[] fileIds) {
        if (fileIds == null || fileIds.length == 0) {
            return new ArrayList<>();
        }
        return fileMapper.selectFileInfosByIds(fileIds);
    }
    
    @Override
    public List<FileInfo> selectFileList(FileInfo fileInfo) {
        return fileMapper.selectFileList(fileInfo);
    }
    
    @Override
    public void downloadFile(Long fileId, HttpServletResponse response) {
        if (fileId == null) {
            throw new ServiceException("文件ID不能为空");
        }
        
        // 1. 查询文件信息
        FileInfo fileInfo = fileMapper.selectFileInfoById(fileId);
        if (fileInfo == null || "2".equals(fileInfo.getDelFlag())) {
            throw new ServiceException("文件不存在或已删除");
        }
        
        // 2. 构建完整文件路径
        // file_path存储的是相对路径（如：/profile/upload/2025/11/05/test.pdf）
        // 使用FileUtils.stripPrefix()去掉/profile前缀，然后拼接RuoYiConfig.getProfile()获取完整路径
        String relativePath = FileUtils.stripPrefix(fileInfo.getFilePath());
        // 拼接完整路径
        String filePath = RuoYiConfig.getProfile() + relativePath;
        
        // 3. 检查文件是否存在
        File file = new File(filePath);
        if (!file.exists() || !file.isFile()) {
            log.warn("文件不存在，fileId: {}, filePath: {}", fileId, filePath);
            throw new ServiceException("文件不存在");
        }
        
        // 4. 下载文件（下载成功后再更新下载次数）
        try {
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, fileInfo.getOriginalName());
            FileUtils.writeBytes(filePath, response.getOutputStream());
            
            // 5. 下载成功后异步更新下载次数（失败不影响下载）
            try {
                fileInfo.setDownloadCount(fileInfo.getDownloadCount() + 1);
                fileMapper.updateFileInfo(fileInfo);
            } catch (Exception e) {
                // 下载次数更新失败不影响下载，只记录日志
                log.warn("更新文件下载次数失败，fileId: {}", fileId, e);
            }
        } catch (Exception e) {
            log.error("文件下载失败，fileId: {}, filePath: {}", fileId, filePath, e);
            throw new ServiceException("文件下载失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public int deleteFile(Long fileId) {
        if (fileId == null) {
            throw new ServiceException("文件ID不能为空");
        }
        
        // 1. 查询文件信息
        FileInfo fileInfo = fileMapper.selectFileInfoById(fileId);
        if (fileInfo == null || "2".equals(fileInfo.getDelFlag())) {
            throw new ServiceException("文件不存在或已删除");
        }
        
        // 2. 权限校验：只能删除自己上传的文件（或管理员）
        Long userId = SecurityUtils.getUserId();
        // 防止空指针异常
        if (fileInfo.getUploadUserId() != null && !fileInfo.getUploadUserId().equals(userId) && !SecurityUtils.isAdmin(userId)) {
            log.warn("用户尝试删除无权限的文件，userId: {}, fileId: {}, uploadUserId: {}", 
                    userId, fileId, fileInfo.getUploadUserId());
            throw new ServiceException("无权删除该文件");
        }
        // 如果uploadUserId为null（系统文件），需要管理员权限
        if (fileInfo.getUploadUserId() == null && !SecurityUtils.isAdmin(userId)) {
            log.warn("非管理员尝试删除系统文件，userId: {}, fileId: {}", userId, fileId);
            throw new ServiceException("无权删除该文件");
        }
        
        // 3. 逻辑删除（标记删除标志和状态）
        fileInfo.setDelFlag("2");
        fileInfo.setStatus(FileStatus.DELETED.getCode()); // 使用枚举
        fileInfo.setUpdateBy(SecurityUtils.getUsername());
        int result = fileMapper.updateFileInfo(fileInfo);
        log.info("文件逻辑删除成功，fileId: {}, uploadUserId: {}", fileId, fileInfo.getUploadUserId());
        
        // 注意：物理删除文件可以后续通过定时任务清理
        return result;
    }
}