package http.net;

import android.annotation.SuppressLint;
import android.app.DownloadManager;
import android.content.ContentUris;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.util.SparseArray;

import com.blankj.utilcode.util.FileUtils;

import java.lang.ref.WeakReference;
import java.util.function.Consumer;

/**
 * 下载文件
 *
 * @author Jayce
 */
@SuppressLint("Range")
public class DownloadHelper {
    private static final String TAG = "DownloadHelper";
    private final Context context; // 应用上下文，使用ApplicationContext避免内存泄漏
    private final DownloadManager downloadManager; // 系统下载管理器实例
    private final SparseArray<DownloadTask> downloadTasks = new SparseArray<>(); // 存储所有下载任务，key为自定义任务ID
    private final Handler handler; // 主线程Handler，用于执行回调

    public DownloadHelper(Context context) {
        this.context = context.getApplicationContext();
        // 获取系统下载服务
        this.downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
        // 创建主线程Handler用于回调
        this.handler = new Handler(Looper.getMainLooper());
    }

    // 下载回调接口
    public interface DownloadCallback {
        void onProgress(int progress, long downloadedBytes, long totalBytes); // 下载进度更新

        void onSuccess(Uri fileUri);         // 下载成功

        void onFailure(int reason);          // 下载失败（携带系统错误码）

        void onPaused();                     // 下载暂停

        void onCancelled();                  // 下载取消
    }

    // 下载任务封装类
    private static class DownloadTask {
        final long downloadId;               // 系统分配的下载ID
        final WeakReference<DownloadCallback> callbackRef; // 使用弱引用防止内存泄漏
        final ContentObserver observer;      // 内容观察者，用于监听下载状态变化

        DownloadTask(long downloadId, DownloadCallback callback, ContentObserver observer) {
            this.downloadId = downloadId;
            this.callbackRef = new WeakReference<>(callback);
            this.observer = observer;
        }
    }

    /**
     * 启动下载任务
     *
     * @param url      下载地址
     * @param fileName 保存文件名
     * @param taskId   自定义任务ID（用于区分不同任务）
     * @param callback 下载状态回调
     */
    public void startDownload(String url, String fileName, int taskId, DownloadCallback callback) {
        // 检查任务是否已存在
        if (downloadTasks.get(taskId) != null) {
            Log.w(TAG, "Task already exists: " + taskId);
            return;
        }

        try {
            @SuppressLint("SdCardPath") final String filePathDir = "/sdcard/" + Environment.DIRECTORY_DOWNLOADS + "/file/";
            FileUtils.createOrExistsDir(filePathDir);
            FileUtils.deleteAllInDir(filePathDir);
            // 创建下载请求
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url))
                    .setTitle(fileName)
                    .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE) // 显示系统通知
                    .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "file/" + fileName); // 保存到公共下载目录

            long downloadId = downloadManager.enqueue(request); // 加入下载队列
            ContentObserver observer = registerObserver(downloadId, callback); // 注册内容观察者
            downloadTasks.put(taskId, new DownloadTask(downloadId, callback, observer)); // 记录任务信息
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Invalid download URL", e);
            notifyCallback(callback, true, c -> c.onFailure(DownloadManager.ERROR_UNKNOWN)); // 通知无效URL错误
        }
    }

    /**
     * 取消指定下载任务
     *
     * @param taskId 自定义任务ID
     */
    public void cancelDownload(int taskId) {
        DownloadTask task = downloadTasks.get(taskId);
        if (task != null) {
            try {
                downloadManager.remove(task.downloadId); // 从下载管理器移除
            } catch (IllegalArgumentException e) {
                Log.w(TAG, "Download already removed: " + task.downloadId);
            }
            unregisterObserver(task.observer); // 注销观察者
            notifyCallback(task.callbackRef, true, DownloadCallback::onCancelled); // 触发取消回调
            downloadTasks.remove(taskId); // 移除任务记录
        }
    }

    /**
     * 注册内容观察者监听下载状态
     *
     * @param downloadId 系统下载ID
     * @param callback   下载回调
     * @return 注册的内容观察者实例
     */
    private ContentObserver registerObserver(long downloadId, DownloadCallback callback) {
        // 构建指定下载任务的URI
        Uri uri = ContentUris.withAppendedId(
                Uri.parse("content://downloads/my_downloads"), downloadId);

        ContentObserver observer = new ContentObserver(handler) {
            private int lastProgress = -1; // 上次进度，用于避免重复回调

            @Override
            public void onChange(boolean selfChange) {
                Cursor cursor = null;
                try {
                    // 查询下载状态
                    cursor = downloadManager.query(new DownloadManager.Query().setFilterById(downloadId));
                    if (cursor != null && cursor.moveToFirst()) {
                        int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
                        long bytesDownloaded = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                        long bytesTotal = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));

                        // 根据状态分发处理
                        switch (status) {
                            case DownloadManager.STATUS_RUNNING:
                                handleProgress(bytesDownloaded, bytesTotal);
                                break;
                            case DownloadManager.STATUS_SUCCESSFUL:
                                handleSuccess();
                                break;
                            case DownloadManager.STATUS_FAILED:
                                handleFailure(cursor);
                                break;
                            case DownloadManager.STATUS_PAUSED:
                                handlePaused();
                                break;
                        }
                    }
                } catch (Exception e) {
                    Log.e(TAG, "Error processing download update", e);
                } finally {
                    if (cursor != null && !cursor.isClosed()) {
                        cursor.close(); // 确保关闭Cursor
                    }
                }
            }

            // 处理下载进度更新
            private void handleProgress(long downloaded, long total) {
                int progress = total > 0 ? (int) ((downloaded * 100L) / total) : 0;
                if (progress != lastProgress) { // 避免相同进度重复回调
                    lastProgress = progress;
                    notifyCallback(callback, false, c -> c.onProgress(progress, downloaded, total));
                }
            }

            // 处理下载成功
            private void handleSuccess() {
                try {
                    Uri uri = downloadManager.getUriForDownloadedFile(downloadId);
                    notifyCallback(callback, true, c -> c.onSuccess(uri));
                } catch (SecurityException e) {
                    Log.e(TAG, "File access permission denied", e);
                    notifyCallback(callback, true, c -> c.onFailure(DownloadManager.ERROR_FILE_ERROR));
                } finally {
                    unregisterObserver(this); // 无论成功失败都注销观察者
                }
            }

            // 处理下载失败
            private void handleFailure(Cursor cursor) {
                int reason = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_REASON));
                notifyCallback(callback, true, c -> c.onFailure(reason));
                unregisterObserver(this);
            }

            // 处理下载暂停
            private void handlePaused() {
                notifyCallback(callback, false, DownloadCallback::onPaused);
            }
        };

        context.getContentResolver().registerContentObserver(uri, true, observer);
        return observer;
    }

    // 注销内容观察者
    private void unregisterObserver(ContentObserver observer) {
        try {
            context.getContentResolver().unregisterContentObserver(observer);
        } catch (Exception e) {
            Log.w(TAG, "Error unregistering observer", e);
        }
    }

    /**
     * 安全执行回调（主线程）
     *
     * @param callback      回调实例
     * @param finalCallback 是否最终回调（触发后清除引用）
     * @param action        要执行的回调操作
     */
    private void notifyCallback(DownloadCallback callback, boolean finalCallback,
                                Consumer<DownloadCallback> action) {
        notifyCallback(new WeakReference<>(callback), finalCallback, action);
    }

    // 带弱引用的回调方法
    private void notifyCallback(WeakReference<DownloadCallback> ref, boolean finalCallback,
                                Consumer<DownloadCallback> action) {
        handler.post(() -> {
            DownloadCallback callback = ref.get();
            if (callback != null) {
                try {
                    action.accept(callback); // 执行回调
                } catch (Exception e) {
                    Log.e(TAG, "Callback execution error", e);
                }
            }
            if (finalCallback) {
                ref.clear(); // 清除弱引用
            }
        });
    }

    /**
     * 释放所有资源（建议在不再需要时调用）
     */
    public void release() {
        for (int i = 0; i < downloadTasks.size(); i++) {
            DownloadTask task = downloadTasks.valueAt(i);
            unregisterObserver(task.observer); // 注销所有观察者
            notifyCallback(task.callbackRef, true, DownloadCallback::onCancelled); // 通知取消
        }
        downloadTasks.clear(); // 清空任务列表
    }
}