package com.kingdee.eas.custom.esign.util;

import okhttp3.*;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 下载文件工具类
 * description: Downloader <br>
 * date: 18/11/2025 下午 4:25 <br>
 * author: lhbj <br>
 * version: 1.0 <br>
 */
public class DownloaderUtil {

    /**
     * 异步接口
     */
    public interface Listener {
        void onSuccess(String data);
        void onError(String error);
    }
    /**
     * 异步接口
     */
    public interface CallbackBytes {
        void onSuccess(byte[] bytes);
        void onError(String error);
    }
    /**
     * 异步
     * 进度条监听类接口
     */
    public interface ProgressListener extends Listener{
        void onProgress(int percentage, long downloaded, long total);
    }
    /**
     * 异步下载
     * 由于返回byte数组，使用时需要注意下载文件大小，不能过大，不能多线程调用，以规避内存风险。
     * @param url
     * @param callback 回调实现类
     */
    public static void downloadFileToByteArrayAsync(String url,
                                                    final CallbackBytes callback) {
        downloadFileToByteArrayAsync(url,null,callback);
    }
    /**
     * 异步下载
     * 由于返回byte数组，使用时需要注意下载文件大小，不能过大，不能多线程调用，以规避内存风险。
     * @param url
     * @param headers 请求头
     * @param callback 回调实现类
     */
    public static void downloadFileToByteArrayAsync(String url,Map<String, String> headers,
                                            final CallbackBytes callback) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callback.onError(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (!response.isSuccessful()) {
                    callback.onError("HTTP " + response.code());
                    return;
                }
                InputStream inputStream = null;
                try {

                    ResponseBody body=response.body();
                    long contentLength =body.contentLength();

                    inputStream = body.byteStream();
                    callback.onSuccess(IOUtils.toByteArray(inputStream));
                } catch (Exception e) {
                    callback.onError("文件保存失败: " + e.getMessage());
                } finally {
                    closeQuietly(inputStream);

                    if (response != null) {
                        response.close();
                    }
                }
            }
        });
    }
    /**
     * 进度条下载
     * @param url
     * @param outputPath 保存下载文件地址
     * @param listener 进度条监听类接口
     */
    public static void downloadWithProgress(String url, String outputPath,
                                            final ProgressListener listener) {
        downloadWithProgress(url,outputPath,null,listener);
    }
    public static void downloadWithProgress(String url, String outputPath,Map<String, String> headers,
                                            final ProgressListener listener) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                listener.onError(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (!response.isSuccessful()) {
                    listener.onError("HTTP " + response.code());
                    return;
                }

                long contentLength = response.body().contentLength();
                InputStream inputStream = null;
                FileOutputStream outputStream = null;

                try {
                    inputStream = response.body().byteStream();
                    File file = new File(outputPath);
                    outputStream = new FileOutputStream(file);

                    byte[] buffer = new byte[8192];
                    int bytesRead;
                    long totalBytesRead = 0;

                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                        totalBytesRead += bytesRead;

                        // 更新进度
                        if (contentLength > 0) {
                            int progress = (int) (totalBytesRead * 100 / contentLength);
                            listener.onProgress(progress, totalBytesRead, contentLength);
                        }
                    }

                    listener.onSuccess(file.getAbsolutePath());

                } catch (Exception e) {
                    listener.onError("文件保存失败: " + e.getMessage());
                } finally {
                    closeQuietly(inputStream);
                    closeQuietly(outputStream);
                    if (response != null) {
                        response.close();
                    }
                }
            }
        });
    }
    /**
     * 下载文件到byte数组
     * 由于返回byte数组，使用时需要注意下载文件大小，不能过大，不能多线程调用，以规避内存风险。
     * @param url
     * @return
     * @throws IOException
     */
    public static byte[] downloadFileToByteArray(String url) throws IOException {
        return downloadFileToByteArray(url,null);
    }
    /**
     * 携带header下载文件到byte数组
     * 由于返回byte数组，使用时需要注意下载文件大小，不能过大，不能多线程调用，以规避内存风险。
     * @param url
     * @param headers 请求头
     * @return
     * @throws IOException
     */
    public static byte[] downloadFileToByteArray(String url, Map<String, String> headers) throws IOException {
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(240, TimeUnit.SECONDS)
                .readTimeout(240, TimeUnit.SECONDS)
                .writeTimeout(240, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .build();
        Request.Builder requestBuilder = new Request.Builder().url(url);
        // 添加自定义请求头
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        Request request = requestBuilder.build();
        Response response = null;
        InputStream inputStream = null;
        try {
            response = client.newCall(request).execute();
            if (!response.isSuccessful()) {
                throw new IOException("下载失败: " + response.code());
            }
            inputStream = response.body().byteStream();
            return IOUtils.toByteArray(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            // 手动关闭资源
            closeQuietly(inputStream);
            if (response != null) {
                response.close();
            }
        }
    }

    /**
     * 文件下载方法
     * @param url
     * @param savePath 保存下载文件地址
     * @param headers 请求头
     * @return
     */
    public static boolean download(String url, String savePath,Map<String, String> headers) {
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(240, TimeUnit.SECONDS)
                .readTimeout(240, TimeUnit.SECONDS)
                .writeTimeout(240, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .build();
        Request.Builder requestBuilder = new Request.Builder().url(url);
        // 添加自定义请求头
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        Request request = requestBuilder.build();

        Response response = null;
        InputStream inputStream = null;
        FileOutputStream outputStream = null;

        try {
            response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                inputStream = response.body().byteStream();
                outputStream = new FileOutputStream(new File(savePath));

                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                return true;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            closeQuietly(inputStream);
            closeQuietly(outputStream);
            if (response != null) {
                response.close();
            }
        }
        return false;
    }

    private static void closeQuietly(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
                // 静默关闭
            }
        }
    }

    private static void closeQuietly(OutputStream fos) {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
                // 静默关闭
            }
        }
    }
}
