package com.ruoyi.cc.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.cc.model.FsConfProfile;
import com.ruoyi.cc.service.ICcParamsService;
import com.ruoyi.cc.service.IFsConfService;
import com.ruoyi.cc.utils.FsConfPathUtils;
import com.ruoyi.cc.utils.FsEslNameUtils;
import com.ruoyi.cc.utils.ShellUtil;
import com.ruoyi.common.utils.CommonUtils;
import com.ruoyi.common.utils.ExceptionUtil;
import com.ruoyi.common.utils.StringUtils;
import link.thingscloud.freeswitch.esl.EslConnectionUtil;
import link.thingscloud.freeswitch.esl.transport.message.EslMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * freeswitch配置文件控制service层
 */
@Service
@Slf4j
public class FsConfServiceImpl implements IFsConfService {

    private static final List<String> ASR_MODULES = Arrays.asList(
            "mod_xunfei_asr",
            "mod_funasr",
            "mod_aliyun_asr",
            "mod_ali_asr",
            "mod_tx_asr",
            "mod_tx_asr1",
            "mod_chinatelecom_asr"
    );

    @Autowired
    private ICcParamsService ccParamsService;

    @Value("${sysconfig.hide-secret}")
    private String sysConfigHideSecret;

    @Value("${sysconfig.hidden-key-list}")
    private String sysConfigHideKeyList;

    private static final String HW_FINGERPRINT_BIN = "/usr/local/freeswitchvideo/bin/hw_fingerprint";

    /**
     * 检查是否需要隐藏指定的字段值
     * @param fieldName
     * @return
     */
    @Override
    public boolean checkNeedHidden(String fieldName){
        boolean hidden = Boolean.parseBoolean(sysConfigHideSecret);
        if(!hidden){
            return false;
        }
        String[] array = sysConfigHideKeyList.split("/");
        for (String s : array) {
            if(fieldName.toLowerCase().contains(s)){
                return  true;
            }
        }
        return false;
    }


    @Override
    public void setSwitchConf(JSONArray params) {
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        try {
            // 创建DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象
            String switchConfXmlPath = fsConfDirectory + "/autoload_configs/switch.conf.xml";
            Document document = builder.parse(new File(switchConfXmlPath));
            // 获取settings元素
            Element settings = (Element)document.getElementsByTagName("settings").item(0);
            // 更新属性值
            NodeList nodes = settings.getElementsByTagName("param");
            for (int i = 0; i < nodes.getLength(); i++) {
                if (nodes.item(i) instanceof Element) {
                    Element element = (Element) nodes.item(i);
                    log.info(JSONObject.toJSONString(element));
                    for (int j = 0; j < params.size(); j++) {
                        JSONObject param = params.getJSONObject(j);
                        String attrName = param.getString("name");
                        if (attrName.equals(element.getAttribute("name"))) {
                            element.setAttribute("value", param.getString("value").trim());
                        }
                    }
                }
            }
            // 将更新后的Document对象写回XML文件
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            DOMSource source = new DOMSource(document);
            StringWriter writer = new StringWriter();
            transformer.transform(source, new StreamResult(writer));
            String updatedXML = writer.toString();
            // 将updatedXML写入文件
            java.nio.file.Files.write(java.nio.file.Paths.get(switchConfXmlPath), updatedXML.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String restartFs() {
        List<String> commands = new ArrayList<>();

        String fsDeployType = ccParamsService.getParamValueByCode("fs-deploy-type", "native");
        if ("native".equalsIgnoreCase(fsDeployType)) {
            String fsNativeStartUpScript = ccParamsService.getParamValueByCode(
                    "fs-deploy-native-start-up-script",
                    "/usr/local/freeswitchvideo/bin/freeswitch.sh"
            );
            if (!isSafeFsStartupScript(fsNativeStartUpScript)) {
                log.error("fs-deploy-native-start-up-script invalid: {}", fsNativeStartUpScript);
                return "启动脚本路径不合法";
            }
            commands.add("/usr/bin/sh");
            commands.add(fsNativeStartUpScript);
        } else if ("docker".equalsIgnoreCase(fsDeployType)) {
            String fsDockerContainerName = ccParamsService.getParamValueByCode(
                    "fs_docker_container_name",
                    "freeswitchvideo-debian12"
            );
            if (!FsEslNameUtils.isSafeName(fsDockerContainerName)) {
                log.error("fs_docker_container_name invalid: {}", fsDockerContainerName);
                return "容器名称不合法";
            }
            commands.add("docker");
            commands.add("restart");
            commands.add(fsDockerContainerName);
        } else {
            log.error("fs-deploy-type 参数错误!");
            return "fs-deploy-type参数错误";
        }
        try {
            ProcessBuilder processBuilder = new ProcessBuilder(commands);
            Process process = processBuilder.start();

            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                log.info(line);
            }

            BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            String errorLine;
            while ((errorLine = errorReader.readLine()) != null) {
                log.info(errorLine);
            }

            int exitCode = process.waitFor();
            log.info("restartFs exitCode={}", exitCode);
            if (exitCode != 0) {
                return "重启失败，exitCode=" + exitCode;
            }
            return "";
        } catch (Exception e) {
            log.error("restartFs failed", e);
            return "重启失败";
        }
    }

    /**
     * Allow absolute script paths under known FreeSWITCH prefixes; block path tricks.
     */
    private boolean isSafeFsStartupScript(String scriptPath) {
        if (StringUtils.isEmpty(scriptPath) || scriptPath.indexOf('\0') >= 0) {
            return false;
        }
        if (scriptPath.contains("..") || scriptPath.contains(" ")
                || scriptPath.contains(";") || scriptPath.contains("|")
                || scriptPath.contains("&") || scriptPath.contains("`")
                || scriptPath.contains("$") || scriptPath.contains("\n")
                || scriptPath.contains("\r")) {
            return false;
        }
        Path path = Paths.get(scriptPath).normalize();
        if (!path.isAbsolute()) {
            return false;
        }
        String normalized = path.toString().replace('\\', '/');
        return normalized.startsWith("/usr/local/freeswitch")
                || normalized.startsWith("/home/freeswitch")
                || normalized.startsWith("/opt/freeswitch");
    }

    @Override
    public JSONObject getSwitchConf() {
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        JSONObject confAllVars = new JSONObject();
        try {
            // 创建DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象
            String switchConfXmlPath = fsConfDirectory + "/autoload_configs/switch.conf.xml";
            Document document = builder.parse(new File(switchConfXmlPath));
            // 获取settings元素
            Element settings = (Element)document.getElementsByTagName("settings").item(0);
            // 获取属性值
            NodeList nodes = settings.getElementsByTagName("param");
            for (int i = 0; i < nodes.getLength(); i++) {
                if (nodes.item(i) instanceof Element) {
                    Element element = (Element) nodes.item(i);
                    confAllVars.put(element.getAttribute("name"), element.getAttribute("value"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return confAllVars;
    }

    @Override
    public String getAsrengine() {
        String defaultProvider = ccParamsService.getParamValueByCode("fs_call_asr_engine", "");
        String defaultModule = moduleNameByProvider(defaultProvider);
        if (StringUtils.isNotEmpty(defaultModule)) {
            return defaultModule;
        }
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        try {
            // 创建DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象
            String modulesConfXmlPath = fsConfDirectory + "/autoload_configs/modules.conf.xml";
            Document document = builder.parse(new File(modulesConfXmlPath));
            // 获取modules元素
            Element modules = (Element)document.getElementsByTagName("modules").item(0);
            // 获取属性值
            NodeList nodes = modules.getElementsByTagName("load");
            for (int i = 0; i < nodes.getLength(); i++) {
                if (nodes.item(i) instanceof Element) {
                    Element element = (Element) nodes.item(i);
                    String moduleName = element.getAttribute("module");
                    if (isAsrModule(moduleName)){
                        return moduleName;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    @Override
    public String setAsrengine(String asrengine) {
        return ensureAsrengineLoaded(asrengine);
    }

    @Override
    public String ensureAsrengineLoaded(String asrengine) {
        if (StringUtils.isEmpty(asrengine)) {
            return "参数错误!";
        }
        if (!isAsrModule(asrengine.trim())) {
            return "不支持的ASR模块: " + asrengine;
        }
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        try {
            // 创建DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象
            String modulesConfXmlPath = fsConfDirectory + "/autoload_configs/modules.conf.xml";
            Document document = builder.parse(new File(modulesConfXmlPath));
            // 获取modules元素
            Element modules = (Element)document.getElementsByTagName("modules").item(0);
            // 获取属性值
            NodeList nodes = modules.getElementsByTagName("load");
            String targetModule = asrengine.trim();
            for (int i = 0; i < nodes.getLength(); i++) {
                if (nodes.item(i) instanceof Element) {
                    Element element = (Element) nodes.item(i);
                    if (targetModule.equals(element.getAttribute("module"))){
                        return "";
                    }
                }
            }
            Element element = document.createElement("load");
            element.setAttribute("module", targetModule);
            modules.appendChild(element);
            // 将更新后的Document对象写回XML文件
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            DOMSource source = new DOMSource(document);
            StringWriter writer = new StringWriter();
            transformer.transform(source, new StreamResult(writer));
            String updatedXML = writer.toString();
            // 将updatedXML写入文件
            java.nio.file.Files.write(java.nio.file.Paths.get(modulesConfXmlPath), updatedXML.getBytes());
        } catch (Throwable e) {
           String tips = String.format("更新配置文件 modules.conf.xml 失败, {} {}",
                   e.toString(), CommonUtils.getStackTraceString(e.getStackTrace()));
           log.error(tips);
           return tips;
        }
        return "";
    }

    private boolean isAsrModule(String moduleName) {
        return ASR_MODULES.contains(moduleName);
    }

    private String moduleNameByProvider(String provider) {
        if (StringUtils.isEmpty(provider)) {
            return "";
        }
        switch (provider.trim()) {
            case "xunfeiasr":
                return "mod_xunfei_asr";
            case "aliyun":
                return "mod_aliyun_asr";
            case "ali":
                return "mod_ali_asr";
            case "tx":
                return "mod_tx_asr";
            case "tx1":
                return "mod_tx_asr1";
            case "funasr":
                return "mod_funasr";
            case "chinatelecom":
                return "mod_chinatelecom_asr";
            default:
                return "";
        }
    }

    @Override
    public void setVarsConf(JSONArray params) {
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        try {
            // 创建DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象
            String varsConfXmlPath = fsConfDirectory + "/vars.xml";
            Document document = builder.parse(new File(varsConfXmlPath));
            NodeList nodes = document.getElementsByTagName("X-PRE-PROCESS");
            for (int i = 0; i < nodes.getLength(); i++) {
                if (nodes.item(i) instanceof Element) {
                    Element element = (Element) nodes.item(i);
                    log.info(JSONObject.toJSONString(element));
                    for (int j = 0; j < params.size(); j++) {
                        JSONObject param = params.getJSONObject(j);
                        String data = element.getAttribute("data");
                        String name = data.substring(0, data.indexOf("="));
                        String attrName = param.getString("name");
                        if (attrName.equals(name)) {
                            element.setAttribute("data", attrName + "=" + param.getString("value").trim());
                        }
                    }
                }
            }
            // 将更新后的Document对象写回XML文件
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            DOMSource source = new DOMSource(document);
            StringWriter writer = new StringWriter();
            transformer.transform(source, new StreamResult(writer));
            String updatedXML = writer.toString();
            // 将updatedXML写入文件
            java.nio.file.Files.write(java.nio.file.Paths.get(varsConfXmlPath), updatedXML.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public JSONObject getVarsConf() {
        JSONObject confAllVars = new JSONObject();
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        try {
            // 创建DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象
            String varsConfXmlPath = fsConfDirectory + "/vars.xml";
            Document document = builder.parse(new File(varsConfXmlPath));
            // 获取属性值
            NodeList nodes = document.getElementsByTagName("X-PRE-PROCESS");
            for (int i = 0; i < nodes.getLength(); i++) {
                if (nodes.item(i) instanceof Element) {
                    Element element = (Element) nodes.item(i);
                    String data = element.getAttribute("data");
                    if (StringUtils.isNotEmpty(data)) {
                        String name = data.substring(0, data.indexOf("="));
                        String value = data.substring(data.indexOf("=") + 1);
                        confAllVars.put(name, value);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return confAllVars;
    }

    @Override
    public JSONObject getAsrConf(String asrFileName) {
        JSONObject confAllVars = new JSONObject();
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        try {
            // 创建DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象
            String asrConfXmlPath = fsConfDirectory + asrFileName;
            Document document = builder.parse(new File(asrConfXmlPath));
            // 获取settings元素
            Element settings = (Element)document.getElementsByTagName("settings").item(0);
            // 获取属性值
            NodeList nodes = settings.getElementsByTagName("param");
            for (int i = 0; i < nodes.getLength(); i++) {
                if (nodes.item(i) instanceof Element) {
                    Element element = (Element) nodes.item(i);
                    confAllVars.put(element.getAttribute("name"), element.getAttribute("value"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return confAllVars;
    }

    @Override
    public String setAsrConf(JSONArray params, String asrFileName) {
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        try {
            // 创建DocumentBuilderFactory对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 创建DocumentBuilder对象
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 解析XML文件获取Document对象
            String asrConfXmlPath = fsConfDirectory + asrFileName;
            Document document = builder.parse(new File(asrConfXmlPath));
            // 获取settings元素
            Element settings = (Element)document.getElementsByTagName("settings").item(0);
            // 更新属性值
            NodeList nodes = settings.getElementsByTagName("param");
            for (int i = 0; i < nodes.getLength(); i++) {
                if (nodes.item(i) instanceof Element) {
                    Element element = (Element) nodes.item(i);
                    log.info(JSONObject.toJSONString(element));
                    for (int j = 0; j < params.size(); j++) {
                        JSONObject param = params.getJSONObject(j);
                        String attrName = param.getString("name");
                        boolean needHidden = checkNeedHidden(attrName);
                        boolean containsMaskStr =  param.getString("value").contains("****");
                        if (attrName.equals(element.getAttribute("name"))) {
                            if(!needHidden || !containsMaskStr) {
                                element.setAttribute("value", param.getString("value").trim());
                            }
                        }
                    }
                }
            }
            // 将更新后的Document对象写回XML文件
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            DOMSource source = new DOMSource(document);
            StringWriter writer = new StringWriter();
            transformer.transform(source, new StreamResult(writer));
            String updatedXML = writer.toString();
            // 将updatedXML写入文件
            java.nio.file.Files.write(java.nio.file.Paths.get(asrConfXmlPath), updatedXML.getBytes());
        } catch (Exception e) {
            String errorDetails = e.toString() + CommonUtils.getStackTraceString(e.getStackTrace());
            log.error("setAsrConf error: {}", errorDetails);
            return errorDetails;
        }
        return "";
    }

    @Override
    public String getCertWssPen() {
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        String fileName = fsConfDirectory + "/tls/wss.pem";
        StringBuilder content = new StringBuilder();
        if (!new File(fileName).exists()) {
            return "";
        }
        try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
            String line;
            while ((line = br.readLine()) != null) {
                content.append(line).append("\n"); // 追加每一行内容，并添加换行符
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return content.toString();
    }

    @Override
    public void setCertWssPen(String certValue) {
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        String fileName = fsConfDirectory + "/tls/wss.pem";
        if (!new File(fsConfDirectory + "/tls").exists()) {
            new File(fsConfDirectory + "/tls").mkdirs();
        }
        if (!new File(fileName).exists()) {
            try {
                new File(fileName).createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(fileName))) {
            bw.write(certValue);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    @Override
    public String getLicenseValue() {
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        String fileName = fsConfDirectory + "/autoload_configs/license.conf";
        StringBuilder content = new StringBuilder();
        if (!new File(fileName).exists()) {
            return "";
        }
        try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
            String line;
            while ((line = br.readLine()) != null) {
                content.append(line).append("\n"); // 追加每一行内容，并添加换行符
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return content.toString();
    }

    @Override
    public void setLicenseConf(String licenseValue) {
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        String fileName = fsConfDirectory + "/autoload_configs/license.conf";
        if (!new File(fileName).exists()) {
            try {
                new File(fileName).createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(fileName))) {
            bw.write(licenseValue);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public JSONObject getLicenseInfo(){
        return JSONObject.parseObject(ccParamsService.getParamValueByCode("system_license_info", "{}"));
    }

    @Override
    public String getLogs(String uuid, String logFile, String logType) {
        log.info(logFile);
        // Never shell out; filter in-process only. Reject unsafe uuid as defense in depth.
        if (StringUtils.isNotEmpty(uuid) && !FsEslNameUtils.isSafeLogQueryId(uuid)) {
            log.warn("reject unsafe log query id");
            return "";
        }
        String ansiRegex = "\u001b\\[[;\\d]*m";
        StringBuilder logs = new StringBuilder();
        try {
            java.io.File file = new java.io.File(logFile);
            if (!file.exists() || !file.isFile()) {
                log.warn("log file not found: {}", logFile);
                return "";
            }
            if (StringUtils.isBlank(uuid)) {
                java.util.List<String> allLines = java.nio.file.Files.readAllLines(java.nio.file.Paths.get(logFile));
                int start = Math.max(0, allLines.size() - 20);
                for (int i = start; i < allLines.size(); i++) {
                    logs.append(allLines.get(i)).append("\r\n");
                }
            } else {
                try (java.io.BufferedReader br = new java.io.BufferedReader(
                        new java.io.InputStreamReader(new java.io.FileInputStream(logFile), StandardCharsets.UTF_8))) {
                    String line;
                    while ((line = br.readLine()) != null) {
                        if (line.contains(uuid)) {
                            if ("fs".equals(logType)) {
                                try {
                                    logs.append(JSONObject.parseObject(line).getString("log").replaceAll(ansiRegex, ""));
                                } catch (Exception e) {
                                    log.error(ExceptionUtil.getExceptionMessage(e));
                                }
                            } else {
                                logs.append(line).append("\r\n");
                            }
                        }
                    }
                }
            }
        } catch (java.io.IOException e) {
            log.error("Failed to read log file: {}", logFile, e);
        }
        return logs.toString();
    }

    @Override
    public List<FsConfProfile> selectProfileList() {
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        List<FsConfProfile> fsConfProfileList = new ArrayList<>();
        String profilePath = fsConfDirectory + "/sip_profiles";
        File profileDir = new File(profilePath);
        // 过滤出文件夹中所有的文件（非文件夹）
        File[] files = profileDir.listFiles(new FileFilter() {
            public boolean accept(File file) {
                return file.isFile();
            }
        });
        if (files != null) {
            for (File file : files) {
                // 检查文件是否是XML文件
                if (file.getName().endsWith(".xml")) {
                    try {
                        FsConfProfile fsConfProfile = new FsConfProfile();
                        // 创建DocumentBuilderFactory对象
                        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                        // 创建DocumentBuilder对象
                        DocumentBuilder builder = factory.newDocumentBuilder();
                        // 解析XML文件
                        Document document = builder.parse(file);
                        // profile元素
                        Element profile = (Element)document.getElementsByTagName("profile").item(0);
                        fsConfProfile.setProfileName(profile.getAttribute("name"));
                        // 获取settings元素
                        Element settings = (Element)document.getElementsByTagName("settings").item(0);
                        // 获取属性值
                        NodeList nodes = settings.getElementsByTagName("param");
                        for (int i = 0; i < nodes.getLength(); i++) {
                            if (nodes.item(i) instanceof Element) {
                                Element element = (Element) nodes.item(i);
                                if ("sip-port".equals(element.getAttribute("name"))) {
                                    fsConfProfile.setSipPort(element.getAttribute("value"));
                                }
                                if ("sip-ip".equals(element.getAttribute("name"))) {
                                    fsConfProfile.setSipId(element.getAttribute("value"));
                                }
                            }
                        }
                        fsConfProfileList.add(fsConfProfile);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return fsConfProfileList;
    }

    @Override
    public String setProfileConf(String profileName, String profileType, JSONArray params) {
        if (!FsEslNameUtils.isSafeName(profileName)) {
            return "profileName参数不合法";
        }
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        Path profileXml = FsConfPathUtils.resolveProfileXml(fsConfDirectory, profileName);
        Path profileDir = FsConfPathUtils.resolveProfileDir(fsConfDirectory, profileName);
        if (profileXml == null || profileDir == null) {
            return "profile路径不合法";
        }
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            if (!Files.exists(profileXml)) {
                // 新增 profile：仅在模板名安全且模板文件存在时从模板拷贝
                Path templateXml = FsConfPathUtils.resolveTemplateXml(fsConfDirectory, profileType);
                if (templateXml == null || !Files.exists(templateXml)) {
                    return "profile模板不存在或不合法";
                }
                Files.copy(templateXml, profileXml, StandardCopyOption.REPLACE_EXISTING);
                log.info("文件拷贝成功！");
                Files.createDirectories(profileDir);
                log.info("创建文件夹成功！");
            }
            Document document = builder.parse(profileXml.toFile());
            Element profile = (Element) document.getElementsByTagName("profile").item(0);
            profile.setAttribute("name", profileName);
            Element gatways = (Element) document.getElementsByTagName("X-PRE-PROCESS").item(0);
            if (gatways == null) {
                return "profile 模板文件错误，无法读取网关配置节点!";
            }
            gatways.setAttribute("data", profileName + "/*.xml");
            Element settings = (Element) document.getElementsByTagName("settings").item(0);
            NodeList nodes = settings.getElementsByTagName("param");
            for (int j = 0; j < params.size(); j++) {
                JSONObject param = params.getJSONObject(j);
                String attrName = param.getString("name");
                String attrValue = param.getString("value");
                if (StringUtils.isBlank(attrName) || StringUtils.isBlank(attrValue)) {
                    continue;
                }
                boolean newParams = true;
                for (int i = 0; i < nodes.getLength(); i++) {
                    if (nodes.item(i) instanceof Element) {
                        Element element = (Element) nodes.item(i);
                        if (attrName.equals(element.getAttribute("name"))) {
                            newParams = false;
                            element.setAttribute("value", param.getString("value").trim());
                        }
                    }
                }
                if (newParams) {
                    log.info("新增属性:{}", JSONObject.toJSONString(param));
                    Element element = document.createElement("param");
                    element.setAttribute("name", param.getString("name").trim());
                    element.setAttribute("value", param.getString("value").trim());
                    settings.appendChild(element);
                }
            }
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            DOMSource source = new DOMSource(document);
            StringWriter writer = new StringWriter();
            transformer.transform(source, new StreamResult(writer));
            Files.write(profileXml, writer.toString().getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            log.error("修改profile失败", e);
            return "修改profile失败";
        }
        return "";
    }

    @Override
    public JSONObject getProfileConf(String profileName, String profileType) {
        JSONObject confAllVars = new JSONObject();
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        Path profileXml;
        if (StringUtils.isBlank(profileName)) {
            profileXml = FsConfPathUtils.resolveTemplateXml(fsConfDirectory, profileType);
        } else {
            if (!FsEslNameUtils.isSafeName(profileName)) {
                return confAllVars;
            }
            profileXml = FsConfPathUtils.resolveProfileXml(fsConfDirectory, profileName);
        }
        if (profileXml == null) {
            return confAllVars;
        }
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(profileXml.toFile());
            Element settings = (Element) document.getElementsByTagName("settings").item(0);
            NodeList nodes = settings.getElementsByTagName("param");
            for (int i = 0; i < nodes.getLength(); i++) {
                if (nodes.item(i) instanceof Element) {
                    Element element = (Element) nodes.item(i);
                    confAllVars.put(element.getAttribute("name"), element.getAttribute("value"));
                }
            }
        } catch (Exception e) {
            log.error("读取profile配置失败", e);
        }
        return confAllVars;
    }

    @Override
    public void setGwRegisterConf(String orginProfileName, String profileName, String gwName, JSONObject params) {
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        Path template = FsConfPathUtils.resolveTemplateXml(fsConfDirectory, "MRWG1");
        if (template == null) {
            log.error("网关注册模板路径不合法: MRWG1");
            return;
        }
        setGwConf(template.toString(), orginProfileName, profileName, gwName, params);
    }

    @Override
    public void setGwUnRegisterConf(String orginProfileName, String profileName, String gwName, JSONObject params) {
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        Path template = FsConfPathUtils.resolveTemplateXml(fsConfDirectory, "MRWG0");
        if (template == null) {
            log.error("网关非注册模板路径不合法: MRWG0");
            return;
        }
        setGwConf(template.toString(), orginProfileName, profileName, gwName, params);
    }

    @Override
    public String getFingerprintValue() {
        if (!isSafeFsStartupScript(HW_FINGERPRINT_BIN)) {
            log.error("hw_fingerprint bin path invalid: {}", HW_FINGERPRINT_BIN);
            return "";
        }
        String fsDeployType = ccParamsService.getParamValueByCode("fs-deploy-type", "docker");
        try {
            if ("native".equalsIgnoreCase(fsDeployType)) {
                return ShellUtil.execArgs(HW_FINGERPRINT_BIN);
            }
            String containerName = ccParamsService.getParamValueByCode(
                    "fs_docker_container_name",
                    "freeswitchvideo-debian12"
            );
            if (!FsEslNameUtils.isSafeName(containerName)) {
                log.error("fs_docker_container_name invalid: {}", containerName);
                return "";
            }
            return ShellUtil.execArgs("docker", "exec", "-i", containerName, HW_FINGERPRINT_BIN);
        } catch (Exception e) {
            log.error("getFingerprintValue failed", e);
            return "";
        }
    }

    private void setGwConf(String gwTemplate, String orginProfileName, String profileName, String gwName, JSONObject params) {
        if (!FsEslNameUtils.isSafeName(profileName) || !FsEslNameUtils.isSafeName(gwName)) {
            log.error("profileName/gwName 不合法: profileName={}, gwName={}", profileName, gwName);
            return;
        }
        if (StringUtils.isNotEmpty(orginProfileName) && !FsEslNameUtils.isSafeName(orginProfileName)) {
            log.error("orginProfileName 不合法: {}", orginProfileName);
            return;
        }
        String fsConfDirectory = ccParamsService.getParamValueByCode("fs_conf_directory", "");
        Path gatewayXml = FsConfPathUtils.resolveGatewayXml(fsConfDirectory, profileName, gwName);
        Path profileDir = FsConfPathUtils.resolveProfileDir(fsConfDirectory, profileName);
        if (gatewayXml == null || profileDir == null) {
            log.error("网关路径不合法: profileName={}, gwName={}", profileName, gwName);
            return;
        }
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 如果修改了profile，则删除原文件
            if (StringUtils.isNotEmpty(orginProfileName) && !orginProfileName.equals(profileName)) {
                Path originGatewayXml = FsConfPathUtils.resolveGatewayXml(fsConfDirectory, orginProfileName, gwName);
                if (originGatewayXml == null) {
                    log.error("原网关路径不合法: orginProfileName={}, gwName={}", orginProfileName, gwName);
                    return;
                }
                try {
                    Files.delete(originGatewayXml);
                    EslMessage eslMessage1 = EslConnectionUtil.sendSyncApiCommand(
                            "sofia", "profile " + orginProfileName + " killgw " + gwName);
                    if (null != eslMessage1) {
                        log.info(StringUtils.joinWith("/r/n", eslMessage1.getBodyLines().toArray()));
                    }
                    log.info("文件删除成功！");
                } catch (Exception e) {
                    log.error("删除文件失败:{}", originGatewayXml);
                    log.error(ExceptionUtil.getExceptionMessage(e));
                }
            }
            if (!Files.exists(profileDir)) {
                Files.createDirectories(profileDir);
            }
            // 每次都从模板文件里拷贝一份，并覆盖参数值，确保修改是否注册模式时属性正确
            try {
                Files.copy(Paths.get(gwTemplate), gatewayXml, StandardCopyOption.REPLACE_EXISTING);
                log.info("文件拷贝成功！");
            } catch (IOException e) {
                log.error("文件拷贝失败！", e);
                return;
            }
            Document document = builder.parse(gatewayXml.toFile());
            Element gateway = (Element) document.getElementsByTagName("gateway").item(0);
            gateway.setAttribute("name", gwName);
            NodeList nodes = document.getElementsByTagName("param");
            for (String attrName : params.keySet()) {
                String attrValue = params.getString(attrName);
                if (StringUtils.isBlank(attrName) || StringUtils.isBlank(attrValue)) {
                    continue;
                }
                boolean newParams = true;
                for (int i = 0; i < nodes.getLength(); i++) {
                    if (nodes.item(i) instanceof Element) {
                        Element element = (Element) nodes.item(i);
                        if (attrName.equals(element.getAttribute("name"))) {
                            newParams = false;
                            element.setAttribute("value", attrValue.trim());
                        }
                    }
                }
                if (newParams) {
                    log.info("新增属性:{}", attrName);
                    Element element = document.createElement("param");
                    element.setAttribute("name", attrName);
                    element.setAttribute("value", attrValue.trim());
                    gateway.appendChild(element);
                }
            }
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            DOMSource source = new DOMSource(document);
            StringWriter writer = new StringWriter();
            transformer.transform(source, new StreamResult(writer));
            Files.write(gatewayXml, writer.toString().getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            log.error("setGwConf failed", e);
        }
    }

    public static void main(String[] args) {
        String certValue = "123";
        String fileName =  "D:\\liliqiang\\ruoyi\\test\\wss.pem";
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(fileName))) {
            bw.write(certValue);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
