package org.example.FileUploadApi.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
//import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.example.Api.LoggerHandler;
import org.example.Api.OptBaseHandler;
import org.example.Entity.Attributes.RequestCheck;
import org.example.Entity.BaseResponse.BaseResponse;
import org.example.Impl.*;
import org.example.Impl.Sql.factory.AllInOneSqlFactory;
import org.example.Impl.Sql.provider.AllInOneSqlProvider;
import org.example.ModuleApi.ModuleAjaxApi.mapper.CRMapper;
import org.example.ModuleApi.ModuleAjaxApi.mapper.DMCrmMapper;
import org.example.Office.OfficeUtil;
import org.example.Utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.util.WebUtils;

import java.io.*;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static org.example.Utils.ExtentionsUtil.getErrMsg;
import static org.example.Utils.FileUtil.*;
import static org.example.Utils.FormParamUtil.GetParamString;
import static org.example.Utils.NativeExtensionUtils.*;
import static org.example.Utils.RequestUtil.*;
import static org.example.Utils.RequestUtil.hasUploadedFiles;
import static org.example.Utils.UrlDecoderUtils.UrlDecode;

@RestController
@Scope("prototype")
@RequestMapping("/Api/FileUploadApi")
public class FileUploadController extends OptBaseHandler {
    private static final Logger log = LoggerFactory.getLogger(FileUploadController.class);


    @Autowired
    private FileUtil fileUtil;

    // 单一接口入口，处理所有请求
    @RequestMapping(value = "/**", method = {RequestMethod.GET, RequestMethod.POST})
    public void handleRequest(HttpServletRequest Request, HttpServletResponse response) throws Exception {
        // 调用 BaseHandler 的 processRequest 处理逻辑
        super.processRequest(Request);
    }

    // 存储业务方法的处理结果
//    private BaseResponse response;

    @Autowired
    private FileImpl FileImpl;
    @Autowired
    private ModuleImpl moduleImpl;
    @Autowired
    private WebConfigUtil webConfigUtil;
    @Qualifier("baseImpl")
    @Autowired
    private BaseImpl bImpl;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private DbOperator dbOperator;

    @Autowired
    private DataImpl dataImpl;

    private static ModuleEventImpl geteventManager() {
        return ModuleEventImpl.getInstance();
    }

    // 原有的CRM模块参数方法（对应method=getcrmoduleiniparams）
    public void DoCheck() {
        // 实际业务逻辑
        Map<String, Object> finfos = new HashMap<>();

        // 向Map中添加键值对，对应C#的集合初始化器
        finfos.put("filename", GetParamString("filename", ""));
        finfos.put("menucode", GetParamString("menucode", ""));
        finfos.put("key", GetParamString("key", ""));
        finfos.put("value", GetParamString("value", ""));
        finfos.put("fileNo", GetParamString("fileNo", ""));
        // 调用Check方法，获取响应结果
        response = FileImpl.Check(finfos);
    }

    public void DoData() {
        Map<String, Object> finfos = new HashMap<>();

        // 向Map中添加键值对，对应C#的集合初始化器
        finfos.put("username", GetParamString("filename", ""));
        finfos.put("userid", GetParamString("menucode", ""));
        finfos.put("key", GetParamString("key", ""));
        finfos.put("value", GetParamString("value", ""));
        finfos.put("filename", GetParamString("value", ""));
        finfos.put("filesize", GetParamString("value", ""));
        finfos.put("fileNo", GetParamString("value", ""));
        finfos.put("position", GetParamString("fileNo", ""));
        finfos.put("menucode", GetParamString("fileNo", ""));

        HttpServletRequest Request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        InputStream stream = null;
        byte[] bytes = null;
        try {
            stream = Request.getInputStream();
            bytes = new byte[stream.available()];
            stream.read(bytes);
        } catch (IOException e) {
            log.error("Exception caught", e);
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    log.error("Exception caught", e);
                }
            }
        }
        response = FileImpl.Save(bytes, finfos);
    }

    private void DoComplete() {
        Map<String, Object> finfos = new HashMap<>();

        finfos.put("username", GetParamString("filename", ""));
        finfos.put("userid", GetParamString("menucode", ""));
        finfos.put("key", GetParamString("key", ""));
        finfos.put("value", GetParamString("value", ""));
        finfos.put("filename", GetParamString("value", ""));
        finfos.put("filesize", GetParamString("value", ""));
        finfos.put("fileNo", GetParamString("value", ""));
        finfos.put("menucode", GetParamString("fileNo", ""));
        response = FileImpl.AddFileInfo(finfos);
    }

    protected void CheckAttcOper(int oper, String filename, long totsize, String specNo, int fileId) throws SQLException {
        if (getUser().IsClientUser) {
            response.setSuccess(true);
        } else {
//            DataImpl dataImpl = new DataImpl(jdbcTemplate);
            response = dataImpl.GetAttcOperInfo(oper, filename, "", totsize, getUser().UserId, getUser().UserName, specNo, fileId, "", "", 0);
        }
    }

    protected void CheckAttcOper(int oper, String filename, long totsize, String specNo, int fileId, String moduleId, String idValue) throws SQLException {
//        DataImpl dataImpl = new DataImpl(jdbcTemplate);
        response = dataImpl.GetAttcOperInfo(oper, filename, "", totsize, getUser().UserId, getUser().UserName, specNo, fileId, moduleId, idValue, 0);
    }

    protected void CheckAttcOper(int oper, String filename, long totsize, String specNo, int fileId, String moduleId, String idValue, int comfirm) throws SQLException {
//        DataImpl dataImpl = new DataImpl(jdbcTemplate);
        response = dataImpl.GetAttcOperInfo(oper, filename, "", totsize, getUser().UserId, getUser().UserName, specNo, fileId, moduleId, idValue, comfirm);
    }

    @RequestCheck(CheckLogin = true)
    public void DoWebUpload() throws SQLException, UnsupportedEncodingException, UnsupportedEncodingException {

        Request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
        if (Request != null) {
            Request.setCharacterEncoding("UTF-8");
        }

        String filename = decodeFileName(FileImpl.Request("filename", "")).replace(",", "，"),
                folder = FileImpl.Request("folder", "file"),
                uFolder = FileImpl.Request("uFolder", "");
        String fileUrl = FileImpl.Request("url");
        log.debug(String.valueOf("filename : " + filename));
        boolean uname = toBoolean(FileImpl.Request("uname", "")),
                gzip = toBoolean(FileImpl.Request("gzip", ""));
        int comfirm = ToInt32(FileImpl.Request("comfirm", "")),
                encode = ToInt32(FileImpl.Request("encode", "")),
                existDelay = ToInt32(FileImpl.Request("existDelay", ""));

        long position = ToInt64(FileImpl.Request("position", "")),
                totsize = ToInt64(FileImpl.Request("totsize", FileImpl.Request("filesize", "")));

        String idValue = FileImpl.Request("idValue", ""),
                specNo = FileImpl.Request("speciesno", ""),
                stepCode = FileImpl.Request("stepCode", ""),
                fileNo = FileImpl.Request("fileNo", "");
        boolean downLoadFile = !isNullOrEmpty(fileUrl) && fileUrl.startsWith("http");

        if (isNullOrEmpty(specNo) || specNo.equalsIgnoreCase("false")) {
//            DataImpl dataImpl = new DataImpl(jdbcTemplate);
            // 此时 dataImpl 中的 jdbcTemplate 已初始化，可正常调用
            specNo = dataImpl.GetAttcBmpSpec(ModuleId);
            specNo = isNullOrEmpty(specNo) ? "01" : specNo;
        }
        if (!isNullOrEmpty(idValue) && idValue.startsWith("{") && idValue.endsWith("}")) {
            response.setSuccess(false);
            response.setMsg("请选择一条记录进行上传！");
            return;
        }

        Map<String, Object> finfos = new HashMap<>();
        finfos.put("username", getUser().UserName);
        finfos.put("userid", getUser().UserId);
        finfos.put("key", GetParamString("key", ""));
        finfos.put("filename", filename);
        finfos.put("filesize", totsize);
        finfos.put("specNo", specNo);//文档左边树节点编号，可省略，默认模块bmpspec
        finfos.put("fileNo", fileNo);
        finfos.put("comfirm", comfirm);
        finfos.put("stepCode", stepCode);//如果是附件，那么单据审批的步骤码，未审批就是0
        finfos.put("value", idValue);//如果是附件，那么就是记录id，如果是帮助文档，那么就是模块moduleId
        finfos.put("menucode", ModuleId);//如果是附件，那么就是当前模块moduleId，如果是帮助文档，那么就是帮助文档的moduleId(2005_1

        boolean isAttc = !isNullOrEmpty(ModuleId);
        String[] dirTabId = new String[1];
        dirTabId[0] = "";
        String fileVPath = isAttc
//                ? StringFormat.format(WebConfigUtil.PubModelAccFilePath, ModuleId, idValue, fileNo)
                ? dataImpl.GetAcFileFolder(ModuleId, idValue, specNo, dirTabId)
                : folder.startsWith("/") ? folder : StringFormat.format(WebConfigUtil_web.getPubModelFilePath(), folder, ModuleId, DateTimeFormatter.ofPattern("yyyyMMdd") + (isNullOrEmpty(uFolder) ? "" : "/" + uFolder));
        finfos.put("filePath", fileVPath);
        finfos.put("dirTabId", dirTabId);
        if (isAttc && (hasUploadedFiles(Request) && encode != 4 || (position == 0 && totsize > 0))) {
//            String _filename = moduleImpl.GetAttcFileName(ModuleId, idValue, filename);
            String _filename = filename;
            if (!NativeExtensionUtils.isNullOrEmpty(_filename)) {
                filename = _filename;
                finfos.put("renamed", true);
                finfos.put("filename", filename);
            } else {
                //这里对齐c#的判断中的部分
                String localPath = Paths.get(WebConfigUtil.getFilePath(), fileVPath).toString();
                Path fileNamePath = Paths.get(filename).getFileName();
                String fileName = fileNamePath == null ? "" : fileNamePath.toString();
                filename = toBoolean(WebConfigUtil.get("NAttcReName", "0")) ? filename
                        : NativeExtensionUtils.isNullOrEmpty(fileNo) ? FileUtil.CreateAttcFileName(localPath, fileName)
                        : String.format("%s_%s", fileNo, fileName);
                finfos.put("filename", filename);
            }
//            if (isAttc) {

            PathInfo pathInfo = new PathInfo();
            pathInfo.ModuleId = ModuleId;       // ModuleId 属性 = 变量 ModuleId 的值
            pathInfo.IdValue = idValue;         // IdValue 属性 = 变量 idValue 的值
            pathInfo.SpecNo = specNo;           // SpecNo 属性 = 变量 specNo 的值
            pathInfo.TotSize = totsize;         // TotSize 属性 = 变量 totsize 的值
            pathInfo.StepCode = stepCode;       // StepCode 属性 = 变量 stepCode 的值
            pathInfo.FileName = filename;       // FileName 属性 = 变量 filename 的值
            pathInfo.OldFileName = filename;    // OldFileName 属性 = 变量 filename 的值（与FileName相同）
            geteventManager().callBeforeUploadFile(pathInfo, null);
            if (comfirm != 1 && moduleImpl.CheckHasAttcFile(ModuleId, idValue, specNo, filename)) {

                response.setSuccess(false);
                response.setMsg(String.format("文件%s已存在，是否覆盖？", filename));
                response.setData(9);
                return;
            }
            CheckAttcOper(1, filename, totsize, specNo, 0, ModuleId, idValue, comfirm);
            if (!response.isSuccess()) {
                return;
            }
        }
//        if (isAttc && (hasUploadedFiles(Request) || (position == 0 && totsize > 0))) {
//            CheckAttcOper(1, filename, totsize, specNo, 0, ModuleId, idValue, comfirm);
//            if (!response.isSuccess()) {
//                return;
//            }
//        }
        String _debugc = "";


        try {
            if (hasUploadedFiles(Request) && encode != 4) {
                log.debug(String.valueOf("是否进入if,当文件是纯二进制流的时候"));
//                该if进不去(处理纯二进制流文件时)
                ArrayList<Object> resultArray = new ArrayList<>();
                for (int i = 0; i < getUploadedFileCount(Request); i++) {
                    MultipartFile file = ((MultipartHttpServletRequest) Request).getFiles("file").get(i);
                    BaseResponse res = saveFile((MultipartFile) file, fileVPath, uname ? null : file.getOriginalFilename(), "", true);
                    if (res.isSuccess()) {
                        finfos.put("fPath", ((PathInfo) res.getData()).RelativePath);
                        if (file != null) {
                            finfos.put("filename", filename = file.getOriginalFilename());
                        }
                        if (isAttc) {
                            res = moduleImpl.AddAttcFileInfo(finfos);
                        }
                        if (res.isSuccess()) {
                            resultArray.add(res.getData());
                            PathInfo pInfo = null;
                            if (response.getData() instanceof PathInfo) {
                                pInfo = (PathInfo) response.getData();
                            }
                            String savePath = "";
                            StringBuilder vpath = new StringBuilder();
                            String htmlPath = WebConfigUtil_web.getViewDocHtmlPath(savePath, vpath);
                            if (new File(htmlPath).exists()) {
                                new File(htmlPath).delete();
                            }
                        } else {
                            deleteFile(PathUtil.combine(fileVPath, filename), "");
                        }
                    }
                }
                if (resultArray.size() > 0) {
                    response.setSuccess(true);
                    response.setData(resultArray.size() > 1 ? resultArray : resultArray.get(0));
                } else {
                    response.setSuccess(false);
                    response.setMsg("上传失败！");
                }
            } else {
                String content = "";
                byte[] buf = new byte[0];
                if (encode == 1) {
                    content = bImpl.Request("data", "");
                    if (gzip) {
                        byte[] buff = Base64.getDecoder().decode(content);
                        content = GZipUtil.unZip(buff);
                    }
                    buf = Base64.getDecoder().decode(content);
                } else if (encode == 2) {
                    //this.Debug($"接收到文件内容长度{Request.TotalBytes},tot:{totsize}");
                    int len = getTotalBytes(Request);
                    InputStream inputStream = getInputStream(Request);
                    if (len > totsize) {
                        InputStreamReader reader = new InputStreamReader(inputStream, Request.getCharacterEncoding());
                        // 直接通过字节流读取并指定编码（一行代码）
                        //content = new String(inputStream.readAllBytes(), Request.getCharacterEncoding() != null ? Request.getCharacterEncoding() : StandardCharsets.UTF_8.name());
                        String charset = Request.getCharacterEncoding() != null ? Request.getCharacterEncoding() : StandardCharsets.UTF_8.name();
                        byte[] contentBytes = ((ByteArrayInputStream) inputStream).readAllBytes();
                        content = new String(contentBytes, charset);
                        response.setMsg("上传数据流错误，请联系开发者并提供web地址！");
                        response.setSuccess(false);
                    } else {
//                        buf = new byte[len];
//                        inputStream.read(buf, 0, buf.length);
                        buf = ((ByteArrayInputStream) inputStream).readAllBytes();
                    }
                } else if (encode == 3) {
                    InputStream stream = getInputStream(Request);
                    String charset = Request.getCharacterEncoding() != null ? Request.getCharacterEncoding() : StandardCharsets.UTF_8.name();
//                    InputStreamReader reader = new InputStreamReader(stream, charset);
//                    content = _debugc = new String(stream.readAllBytes(), charset);
                    byte[] contentBytes = ((ByteArrayInputStream) stream).readAllBytes();
                    content = _debugc = new String(contentBytes, charset);

                    // 新增：空值/空白校验
                    if (content == null || content.trim().isEmpty()) {
                        response.setSuccess(false);
                        response.setMsg("encode=3 上传数据为空，请检查前端提交内容,并重新上传！");
                        return;
                    }
                    // 分割并过滤空元素
                    String[] rawParts = content.split(",");
                    List<String> validParts = new ArrayList<>();
                    for (String part : rawParts) {
                        String trimmedPart = part.trim();
                        if (!trimmedPart.isEmpty()) {
                            validParts.add(trimmedPart);
                        }
                    }
                    if (validParts.isEmpty()) {
                        throw new RuntimeException("encode=3 上传数据为空，原始内容：" + content);
                    }

                    // 转换字节数组
                    buf = new byte[validParts.size()];
                    for (int i = 0; i < validParts.size(); i++) {
                        buf[i] = convertToByte(validParts.get(i));
                    }
                } else if (encode == 4) {
                    if (hasUploadedFiles(Request)) {
                        // Java中替换C#的MemoryStream + using + CopyTo逻辑
                        MultipartFile file = ((MultipartHttpServletRequest) Request).getFiles("file").get(0);
                        try (InputStream inputStream = file.getInputStream();
                             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                            // 复制流到内存（等效C#的InputStream.CopyTo(ms)）
                            byte[] buffer = new byte[4096];
                            int bytesRead;
                            while ((bytesRead = inputStream.read(buffer)) != -1) {
                                baos.write(buffer, 0, bytesRead);
                            }
                            // 转字节数组（等效C#的ms.ToArray()）
                            buf = baos.toByteArray();
                        } catch (IOException e) {
                            // 增加异常处理，避免崩溃
                            response.setSuccess(false);
                            response.setMsg("读取文件流失败：" + e.getMessage());
                            return;
                        }
                    } else//ios低版本传递不了文件
                    {
                        response.setSuccess(false);
                        response.setData(-1);
                        return;
                    }
                } else if (encode == 5) {
                    InputStream stream = null;
                    try {
                        stream = getInputStream(Request);
                        // 读取Request输入流的全部内容（替换C#的StreamReader.ReadToEnd）
                        content = new String(stream.readAllBytes(),
                                Request.getCharacterEncoding() != null ? Request.getCharacterEncoding() : StandardCharsets.UTF_8.name()).trim();

                        // 处理0x前缀（替换C#的StringComparison.OrdinalIgnoreCase）
                        if (content.startsWith("0x") || content.startsWith("0X")) {
                            content = content.substring(2);
                        }
                        // 补位（长度为奇数时前面加0）
                        if (content.length() % 2 != 0) {
                            content = "0" + content;
                        }

                        // 替换C#的Enumerable.Range + Select（16进制字符串转字节数组）
                        buf = new byte[content.length() / 2];
                        for (int i = 0; i < buf.length; i++) {
                            // 截取2位16进制字符串，转字节（替换C#的Convert.ToByte(...,16)）
                            String hexStr = content.substring(i * 2, i * 2 + 2);
                            buf[i] = (byte) Integer.parseInt(hexStr, 16);
                        }
                    } catch (IOException e) {
                        response.setSuccess(false);
                        response.setMsg("读取16进制流失败：" + e.getMessage());
                        return;
                    } finally {
                        // 关闭流（避免资源泄漏）
                        if (stream != null) {
                            try {
                                stream.close();
                            } catch (IOException e) {
                                log.error("Exception caught", e);
                            }
                        }
                    }
                } else if (!downLoadFile) {
                    InputStream stream = getInputStream(Request);
                    InputStreamReader reader = new InputStreamReader(stream, Request.getCharacterEncoding());
                    content = new String(stream.readAllBytes(), Request.getCharacterEncoding() != null ? Request.getCharacterEncoding() : StandardCharsets.UTF_8.name());
                    buf = Base64.getDecoder().decode(content);
                }
                PathInfo pInfo = null;

                if (buf != null && buf.length > 0 || downLoadFile) {
//                    response = saveFile(buf, position, totsize, fileVPath, filename, FileImpl.getAppDomain(), !isAttc, comfirm == 1 || isAttc ? 1 : 0, isAttc ? "" : FileImpl.getAttcPath());
                    response = saveFile(buf, position, totsize, fileVPath, filename, FileImpl.getAppDomain(), !isAttc, comfirm == 1 || isAttc ? 1 : 0, FileImpl.getAttcPath(), fileUrl);
                    pInfo = (PathInfo) response.getData();
                    if (pInfo != null) {
                        pInfo.UserName = getUser().UserName;
                    }
                }
                if (isAttc && response.isSuccess() && (position + buf.length >= totsize || downLoadFile)) {
                    if (pInfo != null) {
                        //【2】这里的data获得保存的 路径
                        finfos.put("fPath", pInfo.RelativePath);
//                        finfos.put("totTime", OfficeUtil.getVideoInfo(pInfo.SavePath));
                        if (isNullOrEmpty(filename)) {
                            finfos.put("filename", pInfo.FileName);
                        }
                    }
                    response = moduleImpl.AddAttcFileInfo(finfos);
                    log.debug(String.valueOf("data类型: " + response.getData().getClass().getName()));
                    //                    适配pInfo = response.data as FileUtil.PathInfo;
//                    pInfo = (FileUtil.PathInfo) response.getData();
                    if (response.getData() instanceof FileUtil.PathInfo) {
                        // 如果是 PathInfo 类型，安全转换
                        pInfo = (FileUtil.PathInfo) response.getData();
                        // 后续使用 pInfo（非 null）
                    } else if (response.getData() instanceof Integer) {
                        pInfo = null;
                    }

                    String savePath = "";
                    if (pInfo != null) {
                        savePath = pInfo.SavePath;
                    }
                    if (!response.isSuccess()) {
                        if (pInfo != null) {
                            deleteFile(savePath, FileImpl.getAttcPath());
                        }
                    } else {
                        StringBuilder vpath = new StringBuilder();
                        String htmlPath = WebConfigUtil_web.getViewDocHtmlPath(savePath, vpath);
                        File file = new File(htmlPath);
                        if (file.exists()) {
                            boolean isDeleted = file.delete(); // 删除文件
                            if (!isDeleted) {
                                // 可选：处理删除失败的情况
                                log.debug(String.valueOf("文件删除失败: " + htmlPath));
                            }
                        }
                    }
                    if (response.isSuccess() && existDelay > 0 && position + buf.length >= totsize) {
                        String finalFilename = filename;
                        DateTimeUtil.setTimeOut(() -> {
                            deleteFile(PathUtil.combine(fileVPath, finalFilename), getAttcPath());
                        }, existDelay * 1000);
                    }

                }
            }
        } catch (Exception e) {
            LoggerHandler.error(this, String.format("上传错误（模块：%s，主键：%s）：%s", ModuleId, idValue, getErrMsg(e, true)));

            // 2. 设置友好的响应信息（替换通用提示）
            String detailMsg = e.getMessage().contains("unmappable characters") ? String.format("文件名称/路径包含特殊字符，%s,%s,%s，请修改后重新上传", fileVPath, filename, FileImpl.getAttcPath()) :
                    e.getMessage().contains("Connection leak") ? "数据库连接异常，请稍后重试" :
                            e.getMessage().contains("readAllBytes") ? "浏览器兼容问题，请使用Chrome/Firefox上传" :
                                    e.getMessage().contains("权限") ? "服务器文件权限不足，请联系管理员" :
                                            getErrMsg(e);
            response.setData(-1);
            response.setMsg(String.format("上传失败！%s,详细的错误： %s", detailMsg, e.getMessage()));
            response.setSuccess(false);
            // 输出调试信息（对应 C# 的 this.Debug）
//            LoggerHandler.debug(this, String.format("数据流:%s=>%s", encode, _debugc));
//
//            // 输出错误信息（对应 C# 的 this.Error）
//            LoggerHandler.error(this, String.format("上传错误：%s", getErrMsg(e, true)));
//
//            // 设置响应对象信息
//            response.setData(-1);
//            response.setMsg(String.format("上传错误！%s", getErrMsg(e)));
//            response.setSuccess(false);
//            throw new RuntimeException(e);
        } finally {
            // 12. 清理缓存（避免内存泄漏）
            RequestUtil.clearInputStreamCache();
        }
    }

    public void MoveFileTo() {
        String filename = bImpl.Request("filename");
        String filepath = bImpl.Request("filepath", "file");
        String newdir = bImpl.Request("newdir", "");
        String newname = bImpl.Request("newname", "");
        String specno = bImpl.Request("specno", "");
        String sourceId = bImpl.Request("sourceId", "");
        String targetId = bImpl.Request("targetId", "");

        Map<String, Object> finfos = new HashMap<>();
        finfos.put("filepath", filepath);
        finfos.put("newdir", newdir);
        finfos.put("newname", newname);
        finfos.put("filename", filename);
        finfos.put("typeid", bImpl.Request("typeid", "1"));
        finfos.put("ver", bImpl.Request("ver", ""));
        finfos.put("specno", specno);//附件目录节点编号，方便在目录节点之间移动，目录由节点生成那种
        finfos.put("svalue", sourceId);//如果是附件，那么就是记录id，如果是帮助文档，那么就是模块moduleId
        finfos.put("tvalue", targetId);//如果是附件，那么就是记录id，如果是帮助文档，那么就是模块moduleId
//        暂时用不了BaseHandler中的定义参数
//        finfos.put("menucode", ModuleId);//如果是附件，那么就是当前模块moduleId，如果是帮助文档，那么就是帮助文档的moduleId(2005_1)

//        response = moduleImpl.MoveAttcFileInfo(finfos);
    }

    @RequestCheck(CheckLogin = true, CheckParams = "ModuleId,idValue,urls")
    public void DownLoadFiels() throws SQLException {
        String[] urls = (bImpl.Request("urls") != null) ? bImpl.Request("urls").split(";") : new String[0];
        String idValue = bImpl.Request("idValue");
        String speciesno = bImpl.Request("speciesno");
        ArrayList<String> fullUrls = new ArrayList<>();
//        DataImpl dataImpl = new DataImpl(dbOperator);
        boolean hasA = true;
        for (int i = 0; i < urls.length; i++) {
            String u = UrlDecode(urls[i]).split("\\?")[0];
            if (isNullOrEmpty(u)) continue;
            String filename = u.replace("/", "\\").split("\\\\")[new String(u.replace("/", "\\")).split("\\\\").length - 1];
//            System.out.println("ModuleId : " + ModuleId);
//            System.out.println("idValue : " + idValue);
//            System.out.println("filename : " + filename);
            if (!isNullOrEmpty(ModuleId) && !isNullOrEmpty(idValue) && ModuleId != "-1") {
//                System.out.println("123456789");
                response = dataImpl.GetAttcOperInfo(2, filename, dataImpl.GetAttcParentId(ModuleId, idValue), 0, getUser().UserId, getUser().UserName, speciesno, 0, ModuleId, idValue, 0);
                if (!response.isSuccess()) {
                    hasA = false;
                    continue;
                }
            }
            StringBuilder vpth = new StringBuilder();
            String path = toAbsPath(u, FileImpl.getAttcPath(), vpth)[0];
            if (FileUtil.checkFileAuthory(path, getAttcPath())) {
                fullUrls.add(path);
            }
        }
        String zipDict = String.format("%s/downLoadTemp", WebConfigUtil.getFilePath());
        String zipVPath = StringFormat.format("/downLoadTemp/{0}.zip", new java.text.SimpleDateFormat("yyyyMMddhhmmss").format(new java.util.Date()));
        String zipPath = String.format("%s/%s", WebConfigUtil.getFilePath(), zipVPath);

        // 创建 File 对象表示该目录
        File dir = new File(zipDict);

// 判断目录是否不存在：!dir.exists() 表示路径不存在；!dir.isDirectory() 表示路径存在但不是目录
        if (!dir.exists() || !dir.isDirectory()) {
            // 创建目录（包括所有不存在的父目录）
            dir.mkdirs();
        }
        if (fullUrls.size() <= 0) {
            response.setSuccess(false);
            response.setMsg(String.format(
                    "没有可下载的文件%s",
                    hasA ? "" : String.format("，人员对模块%s的下载权限不足，请检查！", ModuleId)
            ));
            return;
        }
        ZipUtil.GoZip(fullUrls.stream().collect(Collectors.joining(";")), zipPath, "");
        DateTimeUtil.setTimeOut(() -> {
            try {
                File zipFile = new File(zipPath);
                if (zipFile.exists()) {  // 对应 C# File.Exists(zipPath)
                    boolean isDeleted = zipFile.delete();  // 对应 C# File.Delete(zipPath)
                    if (isDeleted) {
                        log.debug(String.valueOf("文件已成功删除：" + zipPath));
                    } else {
                        log.warn(String.valueOf("文件删除失败（可能被占用或无权限）：" + zipPath));
                    }
                } else {
                    log.debug(String.valueOf("文件不存在，无需删除：" + zipPath));
                }
            } catch (Exception e) {
                // 捕获异常，避免影响主线程
                log.warn(String.valueOf("任务执行失败：" + e.getMessage()));
            }
        }, 600000);
        response.setSuccess(true);
        response.setData(StringFormat.format("/{0}/{1}", WebConfigUtil.getFileVPath(), zipVPath));
    }

    @RequestCheck(CheckLogin = true, Name = "删除附件", CheckParams = "filename|fileid")
    public void DoDelete() throws SQLException, UnsupportedEncodingException {
        String folder = UrlDecode(bImpl.Request("folder", "file"));
        String idValue = bImpl.Request("idValue");
        String fileNo = bImpl.Request("fileNo");
        String filename = UrlDecode(bImpl.Request("filename"));
        String speciesno = bImpl.Request("speciesno");
        String fileId = bImpl.Request("fileId");
        String fName = Arrays.stream(UrlDecode(bImpl.Request("filename")).split("/")).reduce((a, b) -> b).orElse("");
        CheckAttcOper(3, fName, 0, speciesno, ToInt32(fileId), ModuleId, idValue);
        if (!response.isSuccess()) {
            response.setMsg(isNullOrEmpty(response.getMsg()) ? "没有操作权限!" : response.getMsg());
            return;
        }
        folder = isNullOrEmpty(folder) ? filename.replace(fName, "") : folder;
        if (!isNullOrEmpty(getAppDomain())) {
            folder = folder.replace(getAppDomain(), "");
        }
        Map<String, Object> finfos = new HashMap<>();
        finfos.put("filename", filename);
        finfos.put("menucode", ModuleId);
        finfos.put("key", bImpl.Request("key"));
        finfos.put("value", idValue);
        finfos.put("fileNo", fileNo);

        boolean isAttc = !isNullOrEmpty(ModuleId) || !isNullOrEmpty(fileId);
        if (isAttc) {
            if (!isNullOrEmpty(fileId)) {
                log.debug(String.valueOf("1111"));
                response = moduleImpl.DelAttcFile(fileId);
                if (isNullOrEmpty(response.getOther() + "") && !isNullOrEmpty(fName))//第一次未删除到文件，再次删除
                {
                    response = moduleImpl.DelAttcFile(ModuleId, idValue, speciesno, folder, fName);
                }
            } else {
                log.debug(String.valueOf("333333"));
                response = moduleImpl.DelAttcFile(ModuleId, idValue, speciesno, folder, fName);
            }
            // DoDelete();
        } else if (!isNullOrEmpty(Trim(fName))) {
            // string fileVPath =folder.StartsWith("/")?folder: String.Format(Web.Core.Util.WebConfigUtil.PubModelFilePath, folder, ModuleId,DateTime.Now.ToString("yyyyMMdd"));
            //response = FileUtil.DeleteFile(fileVPath, filename);
            response = FileUtil.deleteFile(PathUtil.combine(folder, fName), getAttcPath());
        } else {
            response.setSuccess(true);
        }
    }

    @RequestCheck(Name = "保存显示模式", CheckParams = "ModuleId")
    public void SaveViewModule() {
        boolean succession = dataImpl.SaveAttcViewModule(ModuleId, getUserId(), Integer.parseInt(bImpl.Request("vtype")));
        response.setSuccess(succession);
    }

//    public static long GetVideoInfo(String filePath) {
//        File fileInfo = new File(filePath);
//        String types = ".avi,.wmv,.mpeg,.mp4,.m4v,.mov,.asf,.flv,.f4v,.rmvb,.rm,.3gp,.vob";
//        if (!isNullOrEmpty(fileInfo.getName().lastIndexOf('.')) && types.indexOf(fileInfo.getName().lastIndexOf('.')) > -1) {
//            FFmpegFrameGrabber inputFile = new FFmpegFrameGrabber(filePath);
//            try {
//                // 启动抓取器（相当于 Engine 初始化并准备处理）
//                inputFile.start();
//
//                // 获取元数据（对应 engine.GetMetadata(inputFile)）
//                System.out.println("媒体元数据：");
//                System.out.println("文件路径: " + filePath);
//                System.out.println("格式: " + inputFile.getFormat());
//                System.out.println("时长: " + inputFile.getLengthInTime() + " 毫秒");
//                System.out.println("视频宽度: " + inputFile.getImageWidth());
//                System.out.println("视频高度: " + inputFile.getImageHeight());
//                System.out.println("帧率: " + inputFile.getFrameRate());
//                System.out.println("音频采样率: " + inputFile.getSampleRate());
//
//            } catch (IOException e) {
//                System.err.println("获取媒体元数据失败: " + e.getMessage());
//                e.printStackTrace();
//            } finally {
//                // 释放资源（对应 using 语句的自动释放）
//                try {
//                    inputFile.stop();
//                    inputFile.release();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//            return ToInt32(inputFile.getLengthInTime() / 10000000);
//        } else {
//            return 0;
//        }
//    }

    //    辅助方法   等效于 C# 的 Convert.ToByte(c)
    public static byte convertToByte(String c) {
        if (c == null) {
            log.warn(String.valueOf("convertToByte 输入为null"));
            throw new NumberFormatException("输入不能为null");
        }

        String trimmed = c.trim();
        if (trimmed.isEmpty()) {
            log.warn(String.valueOf("convertToByte 输入为空字符串，原始值：" + c));
            throw new NumberFormatException("输入不能为空字符串");
        }
        try {
            int value = Integer.parseInt(trimmed);
            // 严格检查范围
            if (value < 0 || value > 255) {
                log.warn(String.valueOf("convertToByte 值超出范围：" + value + "（原始值：" + c + "）"));
                throw new NumberFormatException("值超出范围：" + value + "（必须在 0~255 之间）");
            }
            return (byte) value;
        } catch (NumberFormatException e) {
            log.warn(String.valueOf("convertToByte 转换失败，原始值：" + c + "，异常：" + e.getMessage()));
            throw e; // 保留异常，但增加日志便于排查
        }
    }

    private String decodeFileName(String encodedFilename) {
        if (encodedFilename == null || encodedFilename.isEmpty()) {
            return encodedFilename;
        }

        if (encodedFilename.contains("%")) {
            return URLDecoder.decode(encodedFilename, StandardCharsets.UTF_8);
        }
        return encodedFilename;
    }


}

