package com.ruoyi.kkfileview.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.kkfileview.config.KkFileViewConfig;
import com.ruoyi.kkfileview.service.FilePreviewService;
import com.ruoyi.kkfileview.service.convert.FileConvertService;
import com.ruoyi.kkfileview.utils.DownloadUtils;
import com.ruoyi.kkfileview.utils.FileTypeUtils;

/**
 * 文件预览服务实现类
 * 
 * @author jackeyhuang
 * @version 1.0.0
 * @date 2026-01-11
 */
@Service
public class FilePreviewServiceImpl implements FilePreviewService
{
    private static final Logger log = LoggerFactory.getLogger(FilePreviewServiceImpl.class);

    @Autowired
    private KkFileViewConfig config;

    @Autowired(required = false)
    private List<FileConvertService> convertServices;

    @Override
    public void previewFile(String fileUrl, HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        try
        {
            // 从请求中提取token（如果URL中包含token参数）
            String token = extractTokenFromUrl(fileUrl);
            if (token == null)
            {
                // 尝试从请求头中获取
                String authHeader = request.getHeader("Authorization");
                if (authHeader != null && authHeader.startsWith("Bearer "))
                {
                    token = authHeader.substring(7);
                }
            }
            
            // 1. 下载文件到临时目录
            File tempFile = downloadFileToTemp(fileUrl, token);
            if (tempFile == null || !tempFile.exists())
            {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                response.setContentType("text/html;charset=UTF-8");
                response.getWriter().write("文件下载失败或文件不存在");
                return;
            }

            // 2. 获取文件类型
            String fileType = FileTypeUtils.getFileType(tempFile.getName());
            log.info("预览文件类型: {}, 文件: {}", fileType, tempFile.getName());

            // 3. 根据文件类型处理
            if (FileTypeUtils.isImageFile(fileType))
            {
                // 图片文件直接返回
                serveFile(tempFile, response, FileTypeUtils.detectMimeType(tempFile));
            }
            else if (FileTypeUtils.isPdfFile(fileType))
            {
                // PDF文件直接返回
                serveFile(tempFile, response, "application/pdf");
            }
            else if (FileTypeUtils.isTextFile(fileType))
            {
                // 文本文件直接返回
                serveFile(tempFile, response, "text/plain;charset=UTF-8");
            }
            else if (FileTypeUtils.isOfficeFile(fileType))
            {
                // Office文件需要转换
                handleOfficeFile(tempFile, fileType, response);
            }
            else
            {
                // 其他文件类型，尝试直接返回
                serveFile(tempFile, response, FileTypeUtils.detectMimeType(tempFile));
            }
        }
        catch (Exception e)
        {
            log.error("文件预览失败: {}", fileUrl, e);
            throw e;
        }
    }

    /**
     * 从URL中提取token参数
     */
    private String extractTokenFromUrl(String fileUrl)
    {
        try
        {
            if (fileUrl != null && fileUrl.contains("token="))
            {
                int tokenIndex = fileUrl.indexOf("token=");
                String tokenPart = fileUrl.substring(tokenIndex + 6);
                int endIndex = tokenPart.indexOf("&");
                if (endIndex > 0)
                {
                    return java.net.URLDecoder.decode(tokenPart.substring(0, endIndex), StandardCharsets.UTF_8.name());
                }
                else
                {
                    return java.net.URLDecoder.decode(tokenPart, StandardCharsets.UTF_8.name());
                }
            }
        }
        catch (Exception e)
        {
            log.warn("从URL提取token失败: {}", fileUrl, e);
        }
        return null;
    }

    /**
     * 下载文件到临时目录
     */
    private File downloadFileToTemp(String fileUrl) throws IOException
    {
        return downloadFileToTemp(fileUrl, null);
    }

    /**
     * 下载文件到临时目录（支持传递认证token）
     */
    private File downloadFileToTemp(String fileUrl, String token) throws IOException
    {
        try
        {
            // 创建临时目录
            String tempDir = config.getFileSaveDir();
            if (StringUtils.isEmpty(tempDir))
            {
                tempDir = RuoYiConfig.getProfile() + "/kkfileview/temp";
            }
            
            File tempDirFile = new File(tempDir);
            if (!tempDirFile.exists())
            {
                tempDirFile.mkdirs();
            }

            // 生成临时文件名
            String fileName = DownloadUtils.getFileNameFromUrl(fileUrl);
            if (StringUtils.isEmpty(fileName) || fileName.equals("file"))
            {
                fileName = "temp_" + System.currentTimeMillis();
            }
            
            File tempFile = new File(tempDirFile, fileName);
            
            // 下载文件（传递token用于认证）
            if (DownloadUtils.downloadFile(fileUrl, tempFile, token))
            {
                return tempFile;
            }
            
            return null;
        }
        catch (Exception e)
        {
            log.error("下载文件到临时目录失败: {}", fileUrl, e);
            return null;
        }
    }

    /**
     * 处理Office文件
     */
    private void handleOfficeFile(File sourceFile, String fileType, HttpServletResponse response) throws Exception
    {
        // 查找支持该文件类型的转换服务
        FileConvertService convertService = null;
        if (!CollectionUtils.isEmpty(convertServices))
        {
            for (FileConvertService service : convertServices)
            {
                if (service.supports(fileType))
                {
                    convertService = service;
                    break;
                }
            }
        }

        if (convertService != null)
        {
            // 转换为PDF
            File pdfFile = new File(sourceFile.getParent(), sourceFile.getName() + ".pdf");
            if (convertService.convertToPdf(sourceFile, pdfFile) && pdfFile.exists())
            {
                serveFile(pdfFile, response, "application/pdf");
                return;
            }
        }

        // 如果转换失败，尝试直接返回（浏览器可能支持部分预览）
        log.warn("Office文件转换失败，尝试直接返回: {}", sourceFile.getName());
        serveFile(sourceFile, response, FileTypeUtils.detectMimeType(sourceFile));
    }

    /**
     * 返回文件内容
     */
    private void serveFile(File file, HttpServletResponse response, String contentType) throws IOException
    {
        response.setContentType(contentType);
        response.setHeader("Content-Disposition", "inline; filename=\"" + 
            java.net.URLEncoder.encode(file.getName(), StandardCharsets.UTF_8.name()) + "\"");
        response.setHeader("Cache-Control", "public, max-age=3600");
        // 允许在iframe中加载（kkFileView预览需要）
        response.setHeader("X-Frame-Options", "SAMEORIGIN");
        response.setContentLengthLong(file.length());

        try (FileInputStream fis = new FileInputStream(file);
             OutputStream os = response.getOutputStream())
        {
            IOUtils.copy(fis, os);
            os.flush();
        }
    }
}
