package com.goldenwater.slgc.service.impl.efinder;

import com.goldenwater.slgc.entity.efinder.DocFile;
import com.goldenwater.slgc.mapper.efinder.DocFileMapper;
import com.goldenwater.slgc.service.efinder.IDocFileService;
import com.goldenwater.common.config.RuoYiConfig;
import com.goldenwater.common.utils.file.FileUtils;
import com.goldenwater.common.utils.file.FileUploadUtils;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
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 java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

@Service
@Transactional
public class DocFileServiceImpl implements IDocFileService {
    @Autowired
    private DocFileMapper docFileMapper;

    /**
     * 查询文件列表
     */
    @Override
    public List<DocFile> selectList(DocFile docFile) {
        return docFileMapper.selectList(docFile);
    }

    /**
     * 根据主键查询文件
     */
    @Override
    public DocFile selectById(Long id) {
        return docFileMapper.selectById(id);
    }

    /**
     * 下载文件
     */
    @Override
    public void download(Long id, HttpServletResponse response) {
        DocFile docFile = docFileMapper.selectById(id);
        if (docFile == null || docFile.getPath() == null) {
            return;
        }
        try {
            FileUtils.setAttachmentResponseHeader(response, docFile.getName());
            response.setContentType("application/octet-stream");
            FileUtils.writeBytes(docFile.getPath(), response.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 上传文件
     */
    @Override
    public String upload(MultipartFile file, Long pid) {
        try {
            String url = FileUploadUtils.upload(RuoYiConfig.getProfile(), file);
            String absPath = RuoYiConfig.getProfile() + "/" + url.replace("/profile/", "");
            DocFile docFile = new DocFile();
            docFile.setName(file.getOriginalFilename());
            docFile.setType(FileUploadUtils.getExtension(file));
            docFile.setSize(file.getSize());
            docFile.setPath(absPath);
            docFile.setDate(new Date());
            docFile.setPid(pid);
            docFileMapper.insert(docFile);
            return url;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 新增文件
     */
    @Override
    public int insert(DocFile docFile) {
        return docFileMapper.insert(docFile);
    }

    /**
     * 修改文件
     */
    @Override
    public int update(DocFile docFile) {
        return docFileMapper.update(docFile);
    }

    /**
     * 删除文件
     */
    @Override
    public int deleteById(Long id) {
        DocFile docFile = docFileMapper.selectById(id);
        if (docFile != null && docFile.getPath() != null) {
            FileUtils.deleteFile(docFile.getPath());
        }
        return docFileMapper.deleteById(id);
    }

    /**
     * 批量删除文件
     */
    @Override
    public int deleteByIds(Long[] ids) {
        for (Long id : ids) {
            DocFile docFile = docFileMapper.selectById(id);
            if (docFile != null && docFile.getPath() != null) {
                FileUtils.deleteFile(docFile.getPath());
            }
        }
        return docFileMapper.deleteByIds(ids);
    }

    /**
     * 根据父ID查询文件列表
     */
    @Override
    public List<DocFile> selectByParentId(Long parentId) {
        return docFileMapper.selectByParentId(parentId);
    }

    @Override
    public String readTextContent(Long id, String charset) {
        DocFile docFile = docFileMapper.selectById(id);
        if (docFile == null || docFile.getPath() == null) {
            return null;
        }
        File file = new File(docFile.getPath());
        if (!file.exists() || !file.isFile()) {
            return null;
        }
        if (file.length() > 5 * 1024 * 1024) {
            throw new RuntimeException("File size exceeds 5MB limit");
        }
        try {
            String enc = (charset != null) ? charset : "UTF-8";
            return IOUtils.toString(new FileInputStream(file), enc);
        } catch (IOException e) {
            throw new RuntimeException("Failed to read text file", e);
        }
    }

    @Override
    public List<Map<String, Object>> listZipEntries(Long id) {
        DocFile docFile = docFileMapper.selectById(id);
        if (docFile == null || docFile.getPath() == null) {
            return Collections.emptyList();
        }
        File file = new File(docFile.getPath());
        if (!file.exists()) {
            return Collections.emptyList();
        }
        List<Map<String, Object>> entries = new ArrayList<>();
        try (ZipFile zipFile = new ZipFile(file)) {
            Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
            while (enumeration.hasMoreElements()) {
                ZipEntry entry = enumeration.nextElement();
                Map<String, Object> entryMap = new HashMap<>();
                entryMap.put("name", entry.getName());
                entryMap.put("size", entry.getSize());
                entryMap.put("compressedSize", entry.getCompressedSize());
                entryMap.put("isDirectory", entry.isDirectory());
                entries.add(entryMap);
            }
        } catch (IOException e) {
            throw new RuntimeException("Failed to read ZIP file", e);
        }
        return entries;
    }

    @Override
    public void downloadZipEntry(Long id, String entryPath, HttpServletResponse response) {
        DocFile docFile = docFileMapper.selectById(id);
        if (docFile == null || docFile.getPath() == null) {
            return;
        }
        File file = new File(docFile.getPath());
        if (!file.exists()) {
            return;
        }
        try (ZipFile zipFile = new ZipFile(file)) {
            ZipEntry entry = zipFile.getEntry(entryPath);
            if (entry == null) {
                return;
            }
            String fileName = entry.getName();
            if (fileName.contains("/")) {
                fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
            }
            FileUtils.setAttachmentResponseHeader(response, fileName);
            response.setContentType("application/octet-stream");
            try (InputStream is = zipFile.getInputStream(entry);
                 OutputStream os = response.getOutputStream()) {
                IOUtils.copy(is, os);
                os.flush();
            }
        } catch (IOException e) {
            throw new RuntimeException("Failed to download ZIP entry", e);
        }
    }

    @Override
    public void streamMedia(Long id, HttpServletResponse response) {
        DocFile docFile = docFileMapper.selectById(id);
        if (docFile == null || docFile.getPath() == null) {
            return;
        }
        try {
            String contentType = getMediaContentType(docFile.getName());
            response.setContentType(contentType);
            FileUtils.writeBytes(docFile.getPath(), response.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException("Failed to stream media file", e);
        }
    }

    private String getMediaContentType(String fileName) {
        if (fileName == null) {
            return "application/octet-stream";
        }
        int dotIndex = fileName.lastIndexOf(".");
        if (dotIndex < 0) {
            return "application/octet-stream";
        }
        String ext = fileName.substring(dotIndex + 1).toLowerCase();
        switch (ext) {
            case "mp4":    return "video/mp4";
            case "webm":   return "video/webm";
            case "ogg":    return "video/ogg";
            case "mp3":    return "audio/mpeg";
            case "wav":    return "audio/wav";
            case "flac":   return "audio/flac";
            case "mkv":    return "video/x-matroska";
            case "avi":    return "video/x-msvideo";
            case "mov":    return "video/quicktime";
            case "m3u8":   return "application/x-mpegURL";
            case "ts":     return "video/MP2T";
            case "wma":    return "audio/x-ms-wma";
            case "flv":    return "video/x-flv";
            case "mpeg":
            case "mpg":    return "video/mpeg";
            default:       return "application/octet-stream";
        }
    }
}
