package com.fs.fastgptApi.util;

import com.fs.common.exception.ServiceException;
import com.fs.common.exception.base.BaseException;
import com.fs.fastgptApi.vo.AudioVO;
import com.fs.system.oss.CloudStorageService;
import com.fs.system.oss.OSSFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class AudioUtils {
    /**
     * 工具地址
     **/
    static String path = "c:\\";
    static String destinationDir = "c:\\hook\\";

    /**
     * 从网络 URL 转换 MP3/WAV到SILk格式
     *
     * @param audioUrl  音频文件的 URL
     * @param isSource  是否清空原文件
     * @return SILK 文件路径
     */
    public static AudioVO transferAudioSilkFromUrl(String audioUrl, boolean isSource) {
        try {
            // 下载文件到本地临时路径
            File tempFile = downloadFileFromUrl(audioUrl);
            if (tempFile == null) {
                throw new ServiceException("下载文件失败");
            }

            Integer durations = getDurations(tempFile.getParent()+"\\"+tempFile.getName());
            String silkUrl = transferAudioSilk(tempFile.getParent()+"\\", tempFile.getName(), isSource);
            AudioVO audioVO = new AudioVO();
            audioVO.setDuration(durations);
            audioVO.setUrl(silkUrl);
            // 删除临时文件
            tempFile.delete();

            // 调用原来的转换方法
            return audioVO;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static AudioVO transferAudioSilkFromText(String Text,Long id, boolean isSource) {
        try {
            // 下载文件到本地临时路径
            String tempFile = downloadFileFromText(Text,id);
            if (tempFile == null) {
                throw new ServiceException("下载文件失败");
            }


            Integer durations = getDurations(destinationDir+tempFile);
            String silkUrl = transferAudioSilk(destinationDir, tempFile, isSource);
            AudioVO audioVO = new AudioVO();
            audioVO.setDuration(durations);
            audioVO.setUrl(silkUrl);
            // 调用原来的转换方法
            return audioVO;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static AudioVO transferAudioSilkFromTextNew(String Text,Long id, boolean isSource) {
        try {
            // 下载文件到本地临时路径
            String tempFile = downloadFileFromTextLocalhost(Text,id);
            if (tempFile == null) {
                throw new ServiceException("下载文件失败");
            }
            Integer durations = getDurations(destinationDir+tempFile);
            String silkUrl = transferAudioSilkNew(destinationDir, tempFile, isSource);
            AudioVO audioVO = new AudioVO();
            audioVO.setDuration(durations);
            audioVO.setUrl(silkUrl);
            // 调用原来的转换方法
            return audioVO;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String audioWAVFromUrl(String audioUrl) {
        try {
            // 下载文件到本地临时路径
            File tempFile = downloadFileFromUrl(audioUrl);
            if (tempFile == null) {
                throw new ServiceException("下载文件失败");
            }
            String s = mp3ToWAV(tempFile.getParent() + "\\" + tempFile.getName());
            // 删除临时文件
            tempFile.delete();
            // 调用原来的转换方法
            return s;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
    public  static String mp3ToWAV(String audioFilePath){
        try {
            SimpleDateFormat ttime = new SimpleDateFormat("yyyyMMddhhMMSS");
            String time = ttime.format(new Date());
            // 导出的pcm格式路径
            String WAVPath = destinationDir + "WAV_" + time + ".wav";
            // 构建FFmpeg命令
            String[] command = {
                    path + "ffmpeg.exe",
                    "-i", audioFilePath,WAVPath
            };
            System.out.println(command[2]);
            // 启动进程执行命令
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            processBuilder.redirectErrorStream(true); // 合并标准输出和错误输出
            Process p = processBuilder.start();
            p.waitFor();
            p.destroy();
            return WAVPath;
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    public  static Integer getDurations(String audioFilePath){
        try {
            // 构建FFmpeg命令
            String[] command = {
                    "cmd", "/c", "start", "/b",
                    path + "ffmpeg.exe",
                    "-i", audioFilePath
            };
            // 启动进程执行命令
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            processBuilder.redirectErrorStream(true); // 合并标准输出和错误输出
            Process process = processBuilder.start();

            // 读取进程输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;

            Integer durations=5;
            while ((line = reader.readLine()) != null) {
                // 打印或解析输出信息
                if (line.contains("Duration")) {
                    System.out.println(line);
                    // 查找并解析时长信息
                    String duration = line.substring(line.indexOf("Duration: ") +10, line.indexOf(","));
                    int i = convertDurationToSeconds(duration);
                    System.out.println("音频时长: " + i);
                    durations=i;
                }
            }
            process.waitFor();

            return durations;
        } catch (Exception e) {
            e.printStackTrace();
            return 5;
        }
    }

    private static int convertDurationToSeconds(String duration) {
        try {
            String[] parts = duration.split(":");
            int hours = Integer.parseInt(parts[0]);
            int minutes = Integer.parseInt(parts[1]);
            double seconds = Double.parseDouble(parts[2]); // 包括小数部分
            return (int) (hours * 3600 + minutes * 60 + seconds); // 转换为整数秒
        } catch (Exception e) {
            System.err.println("解析时长字符串失败：" + duration);
            e.printStackTrace();
            return 5;
        }
    }
    /**
//     * MP3/WAV转SILk格式
     *
     * @param path 文件路径 例：D:\\file\\
     * @param name 文件名称 例：audio.mp3/audio.wav
     * @param isSource 是否清空原文件
     * @return silk文件路径
     * @throws Exception
     */
    public static String transferAudioSilk(String path, String name, boolean isSource) {
        try {
            // 判断后缀格式
            String suffix = name.split("\\.")[1];
            if (!suffix.toLowerCase().equals("mp3") && !suffix.toLowerCase().equals("wav")) {
                throw new ServiceException("文件格式必须是mp3/wav");
            }
            String filePath = path + name;
            File file = new File(filePath);
            if (!file.exists()) {
                throw new Exception("文件不存在！");
            }
            // 文件名时拼接
            SimpleDateFormat ttime = new SimpleDateFormat("yyyyMMddhhmmss");
            String time = ttime.format(new Date());
            // 导出的pcm格式路径
            String pcmPath = path + "PCM_" + time + ".pcm";
            // 先将mp3/wav转换成pcm格式
            transferAudioPcm(filePath, pcmPath);
            // 导出的silk格式路径
            String silkPath = path + "SILK_" + time + ".silk";
            // 转换成silk格式
            transferPcmSilk(pcmPath, silkPath);
            // 删除pcm文件
            File pcmFile = new File(pcmPath);
            if (pcmFile.exists()) {
                pcmFile.delete();
            }
            if (isSource) {
                File audioFile = new File(filePath);

                if (audioFile.exists()) {
                    audioFile.delete();
                }
            }

            File silkFile = new File(silkPath);
            //上传silk文件
            String silkPathSuffix = silkPath.split("\\.")[1];
            CloudStorageService storage = OSSFactory.build();
            byte[] fileBytes = Files.readAllBytes(silkFile.toPath());
            String silkUrl = storage.uploadSuffix(fileBytes, "."+silkPathSuffix);

            if (silkFile.exists()) {
                silkFile.delete();
            }
            return silkUrl;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public static String transferAudioSilkNew(String path, String name, boolean isSource) {
        try {
            // 判断后缀格式
            String suffix = name.split("\\.")[1];
            if (!suffix.equalsIgnoreCase("mp3") && !suffix.equalsIgnoreCase("wav")) {
                throw new ServiceException("文件格式必须是mp3/wav");
            }
            String filePath = path + name;
            File file = new File(filePath);
            if (!file.exists()) {
                throw new Exception("文件不存在！");
            }
            // 文件名时拼接
            SimpleDateFormat ttime = new SimpleDateFormat("yyyyMMddhhmmss");
            String time = ttime.format(new Date());
            // 导出的pcm格式路径
            String pcmPath = path + "PCM_" + time + ".pcm";
            // 先将mp3/wav转换成pcm格式
            transferAudioPcm(filePath, pcmPath);
            // 导出的silk格式路径
            String silkPath = path + "SILK_" + time + ".silk";
            // 转换成silk格式
            transferPcmSilk(pcmPath, silkPath);
            // 删除pcm文件
            File pcmFile = new File(pcmPath);
            if (pcmFile.exists()) {
                pcmFile.delete();
            }
            if (isSource) {
                File audioFile = new File(filePath);

                if (audioFile.exists()) {
                    audioFile.delete();
                }
            }

            File silkFile = new File(silkPath);
            int maxAttempts = 20;      // 最多尝试5次
            long intervalMs = 500;   // 每次间隔1秒
            boolean isExists = silkFile.exists();

            for (int i = 0; !isExists && i < maxAttempts; i++) {
                try {
                    Thread.sleep(intervalMs);
                    isExists = silkFile.exists();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new BaseException("文件检测被中断");
                }
            }
            if (!isExists) {
                throw new BaseException("未找到语音文件，生成错误");
            }

            //上传silk文件
            String silkPathSuffix = silkPath.split("\\.")[1];
            CloudStorageService storage = OSSFactory.build();
            byte[] fileBytes = Files.readAllBytes(silkFile.toPath());
            String silkUrl = storage.uploadSuffix(fileBytes, "."+silkPathSuffix);

            if (silkFile.exists()) {
                silkFile.delete();
            }
            return silkUrl;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * mp3/wav 通用
     * @param fpath
     * @param target
     */
    private static void transferAudioPcm(String fpath, String target) {
        System.out.println("pcm地址"+fpath);
        List<String> commend = new ArrayList<String>();
        commend.add("cmd");
        commend.add("/c");
        commend.add("start");
        commend.add("/b");
        commend.add(path + "ffmpeg.exe");
        commend.add("-y");
        commend.add("-i");
        commend.add(fpath);
        commend.add("-f");
        commend.add("s16le");
        commend.add("-ar");
        commend.add("24000");
        commend.add("-ac");
        commend.add("1");
        commend.add(target);
        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commend);
           // builder.inheritIO();
            Process p = builder.start();
            p.waitFor();
            p.destroy();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * silk_v3_encoder.exe，转成Silk格式
     * @param pcmPath pcm 文件地址
     * @param target  转换后的silk地址
     * silk_v3_encoder.exe 路径
     * pcm文件地址
     * silk输出地址
     * -Fs_API <Hz>            : API sampling rate in Hz, default: 24000
     * -Fs_maxInternal <Hz>    : Maximum internal sampling rate in Hz, default: 24000
     * -packetlength <ms>      : Packet interval in ms, default: 20
     * -rate <bps>            : Target bitrate;   default: 25000
     * -loss <perc>          : Uplink loss estimate, in percent (0-100);  default: 0
     * -complexity <comp>   : Set complexity, 0: low, 1: medium, 2: high; default: 2
     * -DTX <flag>          : Enable DTX (0/1); default: 0
     * -quiet               : Print only some basic values
     * -tencent             : Compatible with QQ/Wechat
     */
    public static void transferPcmSilk(String pcmPath, String target) {
        Process process = null;
        try {
            /**
             // 1、这一节的，语音长度太长会使音频长度丢失
             List<String> commend = new ArrayList<>();
             // 指令，可参照方法注释， 请不要在commend.add()里同时写【-参数 值】
             commend.add(path + "silk_v3_encoder.exe");
             commend.add(pcmPath);
             commend.add(target);
             commend.add("-tencent");
             ProcessBuilder builder = new ProcessBuilder();
             builder.command(commend);
             process = builder.start();
             // 如果删除下班这行写process.waitFor() ，太长的语音会阻塞，BufferedReader 打印出来太长的语音也会阻塞
             process = Runtime.getRuntime().exec("taskkill -f -t -im silk_v3_encoder.exe");
             */
            // 方法2，除了会弹出弹窗，没什么问题 cmd /c 极为重要，执行完毕后会自动关闭
            process = Runtime.getRuntime().exec("cmd /c start  " + path + "silk_v3_encoder.exe " + pcmPath + " " + target + " -tencent");
            process .waitFor();
            Thread.sleep(1000);
            // 有更好的方法会后续慢慢更新..
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (process != null) {
                process.destroy();
            }
        }
    }

    public static void transferPcmSilkNew(String pcmPath, String target) {
        Process process = null;
        try {
            List<String> command = new ArrayList<>();
            command.add("cmd");
            command.add("/c");
            command.add("start");
            command.add("/B");
            command.add(path + "silk_v3_encoder.exe");
            command.add(pcmPath);
            command.add(target);
            command.add("-tencent");
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(command);
            Process p = builder.start();
            p.waitFor();
            p.destroy();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 下载文件从网络 URL 到本地临时文件夹
     *
     * @param fileUrl 文件的网络 URL
     * @return 下载到本地的临时文件
     */
    private static File downloadFileFromUrl(String fileUrl) {
        InputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            // 创建 HTTP 连接
            URL url = new URL(fileUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();

            // 检查是否成功连接
            if (connection.getResponseCode() != 200) {
                throw new ServiceException("无法下载音频文件，HTTP 响应码：" + connection.getResponseCode());
            }

            // 获取输入流
            inputStream = connection.getInputStream();

            // 创建临时文件，并指定存放地址
            String tempFileName = "temp_" + System.currentTimeMillis() + "_" + getFileExtension(fileUrl);
            File destinationDirectory = new File(destinationDir);

            // 确保目标目录存在
            if (!destinationDirectory.exists()) {
                destinationDirectory.mkdirs();
            }

            // 将文件保存到指定路径
            File tempFile = new File(destinationDirectory, tempFileName);

            // 写入文件
            outputStream = new FileOutputStream(tempFile);
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }

            return tempFile;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) inputStream.close();
                if (outputStream != null) outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    private static String downloadFileFromText(String text,Long userId) {
        // 创建临时文件，并指定存放地址
        String tempFileName = "temp_" + System.currentTimeMillis() + "_" +userId+ ".wav";
        InputStream inputStream = null;
        FileOutputStream outputStream = null;
        text = text.replaceAll("(哦~|~)", "!")
                .replaceAll("[a-zA-Z]", "")
                .replaceAll("\\s", "");
        try {
            String fileUrl = "http://118.24.209.192:9881/?text="+text+"&ref_audio=./参考音频/companyUser"+userId+".wav&ref_text=在这片神奇的森林里，小鸟轻快地唱着歌，仿佛在诉说着春天的故事。"; // 替换为要下载的文件URL
            try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
                HttpGet httpGet = new HttpGet(fileUrl);
                HttpResponse response = httpClient.execute(httpGet);
                HttpEntity entity = response.getEntity();https://hf-mirror.com
                if (entity != null) {
                     inputStream = entity.getContent();
                    byte[] fileBytes = convertInputStreamToByteArray(inputStream);
                    // 对文件字节数组进行进一步处理
                    String filePath = destinationDir+tempFileName; // 文件将被保存到 C 盘根目录下，文件名为 output_file.wav
                    try (FileOutputStream fos = new FileOutputStream(filePath)) {
                        fos.write(fileBytes);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    EntityUtils.consume(entity); // 释放资源
                }
            } catch (IOException e) {
                e.printStackTrace();
            }



            return tempFileName;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) inputStream.close();
                if (outputStream != null) outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    private static String downloadFileFromTextLocalhost(String text,Long userId) {
        // 创建临时文件，并指定存放地址
        String tempFileName = "temp_" + System.currentTimeMillis() + "_" +userId+ ".wav";
        InputStream inputStream = null;
        FileOutputStream outputStream = null;
        text = text.replaceAll("(哦~|~)", "!")
                .replaceAll("[a-zA-Z]", "")
                .replaceAll("\\s", "");
        try {
            String fileUrl = "http://127.0.0.1:9881/?text="+text+"&ref_audio=./参考音频/companyUser"+userId+".wav&ref_text=在这片神奇的森林里，小鸟轻快地唱着歌，仿佛在诉说着春天的故事。"; // 替换为要下载的文件URL
            try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
                HttpGet httpGet = new HttpGet(fileUrl);
                HttpResponse response = httpClient.execute(httpGet);
                HttpEntity entity = response.getEntity();https://hf-mirror.com
                if (entity != null) {
                     inputStream = entity.getContent();
                    byte[] fileBytes = convertInputStreamToByteArray(inputStream);
                    // 对文件字节数组进行进一步处理
                    String filePath = destinationDir+tempFileName; // 文件将被保存到 C 盘根目录下，文件名为 output_file.wav
                    try (FileOutputStream fos = new FileOutputStream(filePath)) {
                        fos.write(fileBytes);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    EntityUtils.consume(entity); // 释放资源
                }
            } catch (IOException e) {
                e.printStackTrace();
            }



            return tempFileName;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) inputStream.close();
                if (outputStream != null) outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

//    private static File downloadFileFromUrl(String fileUrl)
//    {
//        InputStream inputStream = null;
//        FileOutputStream outputStream = null;
//        try {
//            // 创建 HTTP 连接
//            URL url = new URL(fileUrl);
//            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//            connection.setRequestMethod("GET");
//            connection.connect();
//
//            // 检查是否成功连接
//            if (connection.getResponseCode() != 200) {
//                throw new ServiceException("无法下载音频文件，HTTP 响应码：" + connection.getResponseCode());
//            }
//
//            // 获取输入流
//            inputStream = connection.getInputStream();
//
//            // 创建临时文件
//            String tempFileName = "temp_" + System.currentTimeMillis() + "_" + getFileExtension(fileUrl);
//            File tempFile = new File(tempFileName);
//
//            // 写入文件
//            outputStream = new FileOutputStream(tempFile);
//            byte[] buffer = new byte[8192];
//            int bytesRead;
//            while ((bytesRead = inputStream.read(buffer)) != -1) {
//                outputStream.write(buffer, 0, bytesRead);
//            }
//
//            return tempFile;
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            try {
//                if (inputStream != null) inputStream.close();
//                if (outputStream != null) outputStream.close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
//        return null;
//    }

    /**
     * 获取文件扩展名
     *
     * @param fileUrl 文件路径
     * @return 文件扩展名
     */
    private static String getFileExtension(String fileUrl) {
        return fileUrl.substring(fileUrl.lastIndexOf("."));
    }

    //获取时长
    public static Double getUrlVoiceLength(String wavFilePath) {
        //网络路径，返回的是秒
        if (wavFilePath == null || wavFilePath.length() == 0) {
            return 0D;
        }
        Clip clip = null;
        try {
            clip = AudioSystem.getClip();
            URL url = new URL(wavFilePath);
            AudioInputStream ais = AudioSystem.getAudioInputStream(url);
            clip.open(ais);
            Double v = clip.getMicrosecondLength() / 1000000D;
            return v;
        } catch (Exception e) {
            System.out.println("cuo");
            return null;
        } finally {
            if(clip!=null){
                clip.close();
            }
        }
    }


    private static byte[] convertInputStreamToByteArray(InputStream inputStream) throws IOException {
        ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            byteOutput.write(buffer, 0, bytesRead);
        }
        return byteOutput.toByteArray();
    }
    // 省略其他方法的实现



}
