package com.yushu.system.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yushu.common.utils.DateUtils;
import com.yushu.common.utils.SecurityUtils;
import com.yushu.common.exception.ServiceException;
import com.yushu.common.config.FileStorageConfig;
import com.yushu.system.mapper.SysFileShareMapper;
import com.yushu.system.mapper.SysFileMapper;
import com.yushu.system.mapper.SysFolderMapper;
import com.yushu.system.domain.SysFileShare;
import com.yushu.system.domain.SysFileInfo;
import com.yushu.system.domain.SysFolder;
import com.yushu.system.service.ISysFileShareService;

/**
 * 文件分享Service业务层处理
 * 
 * @author yushu
 * @date 2024-11-15
 */
@Service
public class SysFileShareServiceImpl implements ISysFileShareService 
{
    @Autowired
    private SysFileShareMapper sysFileShareMapper;
    
    @Autowired
    private SysFileMapper sysFileMapper;
    
    @Autowired
    private SysFolderMapper sysFolderMapper;
    
    @Autowired
    private FileStorageConfig fileStorageConfig;

    /**
     * 查询文件分享
     * 
     * @param shareId 文件分享主键
     * @return 文件分享
     */
    @Override
    public SysFileShare selectSysFileShareByShareId(Long shareId)
    {
        return sysFileShareMapper.selectSysFileShareByShareId(shareId);
    }

    /**
     * 根据分享码查询文件分享
     * 
     * @param shareCode 分享码
     * @return 文件分享
     */
    @Override
    public SysFileShare selectSysFileShareByShareCode(String shareCode)
    {
        return sysFileShareMapper.selectSysFileShareByShareCode(shareCode);
    }

    /**
     * 查询文件分享列表
     * 
     * @param sysFileShare 文件分享
     * @return 文件分享
     */
    @Override
    public List<SysFileShare> selectSysFileShareList(SysFileShare sysFileShare)
    {
        return sysFileShareMapper.selectSysFileShareList(sysFileShare);
    }

    /**
     * 创建文件分享
     * 
     * @param fileId 文件ID
     * @param expireDays 过期天数（0表示永久）
     * @param needPassword 是否需要密码
     * @return 文件分享
     */
    @Override
    public SysFileShare createFileShare(Long fileId, Integer expireDays, Boolean needPassword)
    {
        SysFileShare share = new SysFileShare();
        share.setFileId(fileId);
        
        // 生成分享码（8位随机字符串）
        String shareCode = generateShareCode();
        share.setShareCode(shareCode);
        
        // 如果需要密码，生成4位随机密码
        if (needPassword != null && needPassword)
        {
            String password = generatePassword();
            share.setSharePassword(password);
            share.setShareType("1");
        }
        else
        {
            share.setShareType("0");
        }
        
        // 设置过期时间
        if (expireDays != null && expireDays > 0)
        {
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_MONTH, expireDays);
            share.setExpireTime(calendar.getTime());
        }
        
        share.setViewCount(0);
        share.setDownloadCount(0);
        share.setMaxDownload(-1);
        share.setUserId(SecurityUtils.getUserId());
        share.setStatus("0");
        share.setCreateTime(DateUtils.getNowDate());
        share.setCreateBy(SecurityUtils.getUsername());
        
        sysFileShareMapper.insertSysFileShare(share);
        
        return share;
    }
    
    /**
     * 创建文件夹分享
     * 
     * @param folderId 文件夹ID
     * @param expireDays 过期天数（0表示永久）
     * @param needPassword 是否需要密码
     * @return 文件分享
     */
    @Override
    public SysFileShare createFolderShare(Long folderId, Integer expireDays, Boolean needPassword)
    {
        SysFileShare share = new SysFileShare();
        share.setFolderId(folderId);
        share.setResourceType("1"); // 1表示文件夹
        share.setShareCode(generateShareCode());
        share.setShareType(needPassword ? "1" : "0");
        
        if (needPassword)
        {
            share.setSharePassword(generatePassword());
        }
        
        // 设置过期时间
        if (expireDays != null && expireDays > 0)
        {
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_MONTH, expireDays);
            share.setExpireTime(calendar.getTime());
        }
        
        share.setViewCount(0);
        share.setDownloadCount(0);
        share.setMaxDownload(-1);
        share.setUserId(SecurityUtils.getUserId());
        share.setStatus("0");
        share.setCreateTime(DateUtils.getNowDate());
        share.setCreateBy(SecurityUtils.getUsername());
        
        sysFileShareMapper.insertSysFileShare(share);
        
        return share;
    }

    /**
     * 修改文件分享
     * 
     * @param sysFileShare 文件分享
     * @return 结果
     */
    @Override
    public int updateSysFileShare(SysFileShare sysFileShare)
    {
        return sysFileShareMapper.updateSysFileShare(sysFileShare);
    }

    /**
     * 批量删除文件分享
     * 
     * @param shareIds 需要删除的文件分享主键
     * @return 结果
     */
    @Override
    public int deleteSysFileShareByShareIds(Long[] shareIds)
    {
        return sysFileShareMapper.deleteSysFileShareByShareIds(shareIds);
    }

    /**
     * 删除文件分享信息
     * 
     * @param shareId 文件分享主键
     * @return 结果
     */
    @Override
    public int deleteSysFileShareByShareId(Long shareId)
    {
        return sysFileShareMapper.deleteSysFileShareByShareId(shareId);
    }
    
    /**
     * 验证分享
     * 
     * @param shareCode 分享码
     * @param password 提取码
     * @return 文件分享
     */
    @Override
    public SysFileShare verifyShare(String shareCode, String password)
    {
        SysFileShare share = sysFileShareMapper.selectSysFileShareByShareCode(shareCode);
        
        if (share == null)
        {
            throw new ServiceException("分享不存在或已失效");
        }
        
        // 检查状态
        if ("1".equals(share.getStatus()))
        {
            throw new ServiceException("分享已被禁用");
        }
        
        // 检查过期时间
        if (share.getExpireTime() != null && share.getExpireTime().before(new Date()))
        {
            throw new ServiceException("分享已过期");
        }
        
        // 检查下载次数
        if (share.getMaxDownload() != -1 && share.getDownloadCount() >= share.getMaxDownload())
        {
            throw new ServiceException("分享下载次数已达上限");
        }
        
        // 验证密码
        if ("1".equals(share.getShareType()))
        {
            // 需要密码但未提供或密码错误
            if (password == null || password.isEmpty() || !password.equals(share.getSharePassword()))
            {
                throw new ServiceException("提取码错误");
            }
        }
        // shareType为0表示不需要密码，直接通过
        
        // 增加查看次数
        sysFileShareMapper.increaseViewCount(share.getShareId());
        
        // 根据资源类型查询信息
        if ("0".equals(share.getResourceType()))
        {
            // 文件分享
            SysFileInfo fileInfo = sysFileMapper.selectSysFileByFileId(share.getFileId());
            if (fileInfo == null)
            {
                throw new ServiceException("文件不存在");
            }
            share.setFileInfo(fileInfo);
        }
        else if ("1".equals(share.getResourceType()))
        {
            // 文件夹分享 - 查询文件夹内的文件列表（不包含子文件夹的文件）
            SysFileInfo query = new SysFileInfo();
            query.setFolderId(share.getFolderId());
            List<SysFileInfo> fileList = sysFileMapper.selectSysFileList(query);
            share.setFileList(fileList);
        }
        
        return share;
    }
    
    /**
     * 生成分享码（8位随机字符串）
     */
    private String generateShareCode()
    {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 8);
    }
    
    /**
     * 生成提取码（4位随机数字）
     */
    private String generatePassword()
    {
        return String.format("%04d", (int)(Math.random() * 10000));
    }
    
    /**
     * 根据文件ID查询用户的分享
     * 
     * @param fileId 文件ID
     * @return 文件分享
     */
    @Override
    public SysFileShare selectSysFileShareByFileId(Long fileId)
    {
        Long userId = SecurityUtils.getUserId();
        return sysFileShareMapper.selectSysFileShareByFileIdAndUserId(fileId, userId);
    }
    
    /**
     * 根据文件夹ID查询用户的分享
     * 
     * @param folderId 文件夹ID
     * @return 文件分享
     */
    @Override
    public SysFileShare selectSysFileShareByFolderId(Long folderId)
    {
        Long userId = SecurityUtils.getUserId();
        return sysFileShareMapper.selectSysFileShareByFolderIdAndUserId(folderId, userId);
    }
    
    /**
     * 取消文件分享
     * 
     * @param fileId 文件ID
     * @return 结果
     */
    @Override
    public int cancelFileShare(Long fileId)
    {
        return sysFileShareMapper.deleteSysFileShareByFileId(fileId);
    }
    
    /**
     * 通过分享码下载文件
     * 
     * @param shareCode 分享码
     * @param response HTTP响应
     */
    @Override
    public void downloadByShareCode(String shareCode, jakarta.servlet.http.HttpServletResponse response) throws Exception
    {
        // 查询分享信息
        SysFileShare share = sysFileShareMapper.selectSysFileShareByShareCode(shareCode);
        if (share == null)
        {
            throw new ServiceException("分享不存在或已失效");
        }
        
        // 检查状态
        if ("1".equals(share.getStatus()))
        {
            throw new ServiceException("分享已被禁用");
        }
        
        // 检查过期时间
        if (share.getExpireTime() != null && share.getExpireTime().before(new Date()))
        {
            throw new ServiceException("分享已过期");
        }
        
        // 查询文件信息
        SysFileInfo fileInfo = sysFileMapper.selectSysFileByFileId(share.getFileId());
        if (fileInfo == null)
        {
            throw new ServiceException("文件不存在");
        }
        
        // 获取文件完整路径
        String basePath = fileStorageConfig.getLocal().getNormalizedBasePath();
        String fullPath = basePath + File.separator + fileInfo.getFilePath();
        File file = new File(fullPath);
        
        if (!file.exists())
        {
            throw new ServiceException("文件不存在");
        }
        
        // 增加下载次数
        sysFileShareMapper.increaseDownloadCount(share.getShareId());
        
        // 设置响应头
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileInfo.getFileName(), "UTF-8"));
        response.setContentLengthLong(file.length());
        
        // 输出文件
        try (InputStream inputStream = new FileInputStream(file);
             OutputStream outputStream = response.getOutputStream())
        {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1)
            {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
        }
    }
    
    /**
     * 通过分享码和文件ID下载文件（文件夹分享）
     * 
     * @param shareCode 分享码
     * @param fileId 文件ID
     * @param response HTTP响应
     */
    @Override
    public void downloadFileByShareCode(String shareCode, Long fileId, jakarta.servlet.http.HttpServletResponse response) throws Exception
    {
        // 查询分享信息
        SysFileShare share = sysFileShareMapper.selectSysFileShareByShareCode(shareCode);
        if (share == null)
        {
            throw new ServiceException("分享不存在或已失效");
        }
        
        // 检查是否是文件夹分享
        if (!"1".equals(share.getResourceType()))
        {
            throw new ServiceException("不是文件夹分享");
        }
        
        // 检查状态
        if ("1".equals(share.getStatus()))
        {
            throw new ServiceException("分享已被禁用");
        }
        
        // 检查过期时间
        if (share.getExpireTime() != null && share.getExpireTime().before(new Date()))
        {
            throw new ServiceException("分享已过期");
        }
        
        // 查询文件信息
        SysFileInfo fileInfo = sysFileMapper.selectSysFileByFileId(fileId);
        if (fileInfo == null)
        {
            throw new ServiceException("文件不存在");
        }
        
        // 验证文件是否在分享的文件夹中
        if (!fileInfo.getFolderId().equals(share.getFolderId()))
        {
            throw new ServiceException("文件不在分享的文件夹中");
        }
        
        // 获取文件完整路径
        String basePath = fileStorageConfig.getLocal().getNormalizedBasePath();
        String fullPath = basePath + File.separator + fileInfo.getFilePath();
        File file = new File(fullPath);
        
        if (!file.exists())
        {
            throw new ServiceException("文件不存在");
        }
        
        // 增加下载次数
        sysFileShareMapper.increaseDownloadCount(share.getShareId());
        
        // 设置响应头
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileInfo.getFileName(), "UTF-8"));
        response.setContentLengthLong(file.length());
        
        // 输出文件
        try (InputStream inputStream = new FileInputStream(file);
             OutputStream outputStream = response.getOutputStream())
        {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1)
            {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
        }
    }
    
    /**
     * 获取分享文件夹下的子文件夹内容
     * 
     * @param shareCode 分享码
     * @param folderId 文件夹ID
     * @return 文件列表
     */
    @Override
    public List<SysFileInfo> getShareFolderFiles(String shareCode, Long folderId)
    {
        // 查询分享信息
        SysFileShare share = sysFileShareMapper.selectSysFileShareByShareCode(shareCode);
        if (share == null)
        {
            throw new ServiceException("分享不存在或已失效");
        }
        
        // 检查是否是文件夹分享
        if (!"1".equals(share.getResourceType()))
        {
            throw new ServiceException("不是文件夹分享");
        }
        
        // 检查状态
        if ("1".equals(share.getStatus()))
        {
            throw new ServiceException("分享已被禁用");
        }
        
        // 检查过期时间
        if (share.getExpireTime() != null && share.getExpireTime().before(new Date()))
        {
            throw new ServiceException("分享已过期");
        }
        
        // TODO: 验证folderId是否在分享的文件夹树下（需要递归检查）
        // 暂时简化处理，直接查询
        
        // 查询文件夹内的文件
        SysFileInfo query = new SysFileInfo();
        query.setFolderId(folderId);
        return sysFileMapper.selectSysFileList(query);
    }
    
    /**
     * 下载文件夹（打包成ZIP）
     * 
     * @param shareCode 分享码
     * @param folderId 文件夹ID
     * @param response HTTP响应
     */
    @Override
    public void downloadFolderByShareCode(String shareCode, Long folderId, jakarta.servlet.http.HttpServletResponse response) throws Exception
    {
        // 查询分享信息
        SysFileShare share = sysFileShareMapper.selectSysFileShareByShareCode(shareCode);
        if (share == null)
        {
            throw new ServiceException("分享不存在或已失效");
        }
        
        // 检查是否是文件夹分享
        if (!"1".equals(share.getResourceType()))
        {
            throw new ServiceException("不是文件夹分享");
        }
        
        // 检查状态
        if ("1".equals(share.getStatus()))
        {
            throw new ServiceException("分享已被禁用");
        }
        
        // 检查过期时间
        if (share.getExpireTime() != null && share.getExpireTime().before(new Date()))
        {
            throw new ServiceException("分享已过期");
        }
        
        // 查询文件夹信息
        SysFolder folder = sysFolderMapper.selectSysFolderByFolderId(folderId);
        if (folder == null)
        {
            throw new ServiceException("文件夹不存在");
        }
        
        // 设置响应头
        String zipFileName = folder.getFolderName() + ".zip";
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(zipFileName, "UTF-8"));
        
        // 创建ZIP输出流
        try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream()))
        {
            // 递归打包文件夹
            packFolder(folderId, "", zos);
            zos.finish();
        }
        
        // 增加下载次数
        sysFileShareMapper.increaseDownloadCount(share.getShareId());
    }
    
    /**
     * 递归打包文件夹
     */
    private void packFolder(Long folderId, String parentPath, ZipOutputStream zos) throws Exception
    {
        // 查询文件夹内的文件
        SysFileInfo fileQuery = new SysFileInfo();
        fileQuery.setFolderId(folderId);
        List<SysFileInfo> files = sysFileMapper.selectSysFileList(fileQuery);
        
        // 获取文件存储路径
        String basePath = fileStorageConfig.getLocal().getNormalizedBasePath();
        
        // 打包文件
        for (SysFileInfo file : files)
        {
            String filePath = basePath + File.separator + file.getFilePath();
            File diskFile = new File(filePath);
            
            if (diskFile.exists())
            {
                // 添加到ZIP
                String entryName = parentPath + file.getFileName();
                zos.putNextEntry(new ZipEntry(entryName));
                
                try (FileInputStream fis = new FileInputStream(diskFile))
                {
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = fis.read(buffer)) != -1)
                    {
                        zos.write(buffer, 0, bytesRead);
                    }
                }
                
                zos.closeEntry();
            }
        }
        
        // 查询子文件夹
        SysFolder folderQuery = new SysFolder();
        folderQuery.setParentId(folderId);
        List<SysFolder> subFolders = sysFolderMapper.selectSysFolderList(folderQuery);
        
        // 递归打包子文件夹
        for (SysFolder subFolder : subFolders)
        {
            String subPath = parentPath + subFolder.getFolderName() + "/";
            packFolder(subFolder.getFolderId(), subPath, zos);
        }
    }
    
    /**
     * 批量下载（打包成ZIP）
     * 
     * @param shareCode 分享码
     * @param fileIds 文件ID列表
     * @param folderIds 文件夹ID列表
     * @param response HTTP响应
     */
    @Override
    public void downloadBatchByShareCode(String shareCode, List<Long> fileIds, List<Long> folderIds, jakarta.servlet.http.HttpServletResponse response) throws Exception
    {
        // 查询分享信息
        SysFileShare share = sysFileShareMapper.selectSysFileShareByShareCode(shareCode);
        if (share == null)
        {
            throw new ServiceException("分享不存在或已失效");
        }
        
        // 检查状态
        if ("1".equals(share.getStatus()))
        {
            throw new ServiceException("分享已被禁用");
        }
        
        // 检查过期时间
        if (share.getExpireTime() != null && share.getExpireTime().before(new Date()))
        {
            throw new ServiceException("分享已过期");
        }
        
        // 设置响应头
        String zipFileName = "批量下载.zip";
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(zipFileName, "UTF-8"));
        
        // 获取文件存储路径
        String basePath = fileStorageConfig.getLocal().getNormalizedBasePath();
        
        // 创建ZIP输出流
        try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream()))
        {
            int fileCount = 0;
            
            // 打包文件
            if (fileIds != null && !fileIds.isEmpty())
            {
                for (Long fileId : fileIds)
                {
                    SysFileInfo file = sysFileMapper.selectSysFileByFileId(fileId);
                    if (file != null)
                    {
                        String filePath = basePath + File.separator + file.getFilePath();
                        File diskFile = new File(filePath);
                        
                        if (diskFile.exists())
                        {
                            zos.putNextEntry(new ZipEntry(file.getFileName()));
                            
                            try (FileInputStream fis = new FileInputStream(diskFile))
                            {
                                byte[] buffer = new byte[4096];
                                int bytesRead;
                                while ((bytesRead = fis.read(buffer)) != -1)
                                {
                                    zos.write(buffer, 0, bytesRead);
                                }
                            }
                            
                            zos.closeEntry();
                            fileCount++;
                        }
                    }
                }
            }
            
            // 打包文件夹
            if (folderIds != null && !folderIds.isEmpty())
            {
                for (Long folderId : folderIds)
                {
                    SysFolder folder = sysFolderMapper.selectSysFolderByFolderId(folderId);
                    if (folder != null)
                    {
                        String folderPath = folder.getFolderName() + "/";
                        packFolder(folderId, folderPath, zos);
                        fileCount++;
                    }
                }
            }
            
            // 如果没有任何文件，添加一个说明文件
            if (fileCount == 0)
            {
                zos.putNextEntry(new ZipEntry("说明.txt"));
                String content = "此分享暂无文件";
                zos.write(content.getBytes("UTF-8"));
                zos.closeEntry();
            }
            
            zos.finish();
        }
        
        // 增加下载次数
        sysFileShareMapper.increaseDownloadCount(share.getShareId());
    }
}
