/**
 * 录像下载 Helper
 * 从 EZPlayBackListActivity 拆分出来，负责云存储/SD卡录像下载、下载回调、下载文件存储到相册等逻辑
 */
package com.videogo.ui.playback.helper;

import android.Manifest;
import android.os.Build;
import android.widget.ImageButton;

import com.videogo.global.DemoConfig;
import com.videogo.openapi.EZOpenSDKListener;
import com.videogo.openapi.bean.EZCloudRecordFile;
import com.videogo.openapi.bean.EZDeviceRecordFile;
import com.videogo.stream.EZCloudStreamDownload;
import com.videogo.stream.EZDeviceStreamDownload;
import com.videogo.ui.common.EZStreamConfigLoader;
import com.videogo.ui.playback.EZPlayBackListActivity;
import com.videogo.ui.playback.RemoteListUtil;
import com.videogo.ui.playback.download.DownLoadTaskRecordAbstract;
import com.videogo.ui.playback.download.DownloadTaskRecordOfCloud;
import com.videogo.ui.playback.download.DownloadTaskRecordOfDevice;
import com.videogo.util.DataManager;
import com.videogo.util.EZUtils;
import com.videogo.util.LogUtil;
import com.videogo.util.Utils;

import java.io.File;
import java.util.ArrayList;

import ezviz.ezopensdk.R;
import ezviz.ezopensdkcommon.common.EZPermissionUtil;

/**
 * 录像下载 Helper
 * 管理云存储录像下载、SD卡录像下载、下载回调处理、下载文件存储到相册
 * <p>
 * 直接持有 Activity 引用，生命周期与 Activity 一致
 */
public class DownloadHelper {

    private static final String TAG = "DownloadHelper";

    private ImageButton downloadBtn;// 下载按钮

    private final EZPlayBackListActivity mActivity;// Activity 引用
    private final ArrayList<DownLoadTaskRecordAbstract> mDownloadTaskRecordList = new ArrayList<>();// 下载任务列表
    private String downloadFilePath;// 录像下载路径
    private long recordInfoDuration;// 下载的录像时长
    private long mDownloadStartTime = 0;// 录像下载开始时间

    public DownloadHelper(EZPlayBackListActivity activity) {
        this.mActivity = activity;
        initView();
    }

    /**
     * 初始化下载相关视图
     */
    private void initView() {
        downloadBtn = (ImageButton) mActivity.findViewById(R.id.remote_playback_download_btn);
        downloadBtn.setOnClickListener(v -> onDownloadClick());
    }

    // region --- 公开方法 ---

    /**
     * 下载按钮点击
     */
    private void onDownloadClick() {
        mDownloadStartTime = System.currentTimeMillis();
        if (mActivity.mCloudRecordInfo != null) {
            recordInfoDuration = RemoteListUtil.converToSecondDuration(mActivity.mCloudRecordInfo.getStartTime(),
                    mActivity.mCloudRecordInfo.getStopTime());
            startDownloadCloudVideo(mActivity.mCloudRecordInfo);
        } else if (mActivity.mDeviceRecordInfo != null) {
            recordInfoDuration = RemoteListUtil.converToSecondDuration(mActivity.mDeviceRecordInfo.getStartTime(),
                    mActivity.mDeviceRecordInfo.getStopTime());
            startDownloadDeviceVideo(mActivity.mDeviceRecordInfo);
        }
    }

    /**
     * 云存储录像下载 | download video from ezviz cloud
     *
     * @param cloudFile video file of ezviz cloud
     */
    public void startDownloadCloudVideo(final EZCloudRecordFile cloudFile) {
        if (cloudFile == null) {
            return;
        }
        mActivity.submitTask(() -> {
            // 设置下载路径并创建文件
            String strFileNameWithPath = DemoConfig.getRecordsFolder() + "/cloud_" + System.currentTimeMillis() + ".mp4";
            final File file = new File(strFileNameWithPath);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            // 创建下载器
            final EZCloudStreamDownload ezCloudStreamDownloader = new EZCloudStreamDownload(strFileNameWithPath, cloudFile);
            // 云存储录像支持下载进度回调，SD卡录像下载不支持
            ezCloudStreamDownloader.setStreamDownloadCallback(new EZStreamDownloadCallback(cloudFile));
            // 设置下载验证码（录像未加密的话可以不设置）
            ezCloudStreamDownloader.setSecretKey(DataManager.getInstance().getDeviceSerialVerifyCode(mActivity.mCameraInfo.getDeviceSerial()));
            // 如果是双目设备，需要设置
            if (mActivity.isMultiChannelDevice) {
                ezCloudStreamDownloader.setMultiChannelDevice(true);
            }
            // 开始下载
            ezCloudStreamDownloader.start();
            // 记录本次下载任务，onDestory时需要暂停下载任务
            mDownloadTaskRecordList.add(new DownloadTaskRecordOfCloud(ezCloudStreamDownloader));

            Utils.showToast(mActivity, R.string.download_start);
        });
    }

    /**
     * 设备SD卡录像下载 | download video from ezviz device
     *
     * @param deviceFile video file of device SdCard
     */
    public void startDownloadDeviceVideo(final EZDeviceRecordFile deviceFile) {
        if (deviceFile == null) {
            return;
        }
        mActivity.submitTask(() -> {
            // 设置下载路径并创建文件
            String strRecordFilePath = DemoConfig.getRecordsFolder() + "/device_" + System.currentTimeMillis() + ".mp4";
            File file = new File(strRecordFilePath);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            // 创建下载器
            final EZDeviceStreamDownload ezDeviceStreamDownloader = new EZDeviceStreamDownload(strRecordFilePath,
                    mActivity.mCameraInfo.getDeviceSerial(), mActivity.mCameraInfo.getCameraNo(), deviceFile);
            // 设置下载回调监听
            ezDeviceStreamDownloader.setStreamDownloadCallback(new EZStreamDownloadCallback());
            // 设置下载验证码
            ezDeviceStreamDownloader.setSecretKey(DataManager.getInstance().getDeviceSerialVerifyCode(mActivity.mCameraInfo.getDeviceSerial()));
            // 如果是双目设备，需要设置
            if (mActivity.isMultiChannelDevice) {
                ezDeviceStreamDownloader.setMultiChannelDevice(true);
            }
            // 加载SD卡下载特殊配置，一般开发者可不用配置，按需设置
            EZStreamConfigLoader.loadDownloadDeviceVideoSpecialConfigToStreamDownload(ezDeviceStreamDownloader);
            // 开始下载
            ezDeviceStreamDownloader.start();
            // 记录本次下载任务，onDestory时需要暂停下载任务
            mDownloadTaskRecordList.add(new DownloadTaskRecordOfDevice(ezDeviceStreamDownloader));

            Utils.showToast(mActivity, R.string.download_start);
        });
    }

    /**
     * 取消所有下载任务
     */
    public void stopAllDownloadTasks() {
        for (DownLoadTaskRecordAbstract downloadRecord : mDownloadTaskRecordList) {
            downloadRecord.stopDownloader();
        }
    }

    /**
     * 设置下载按钮可用状态
     */
    public void setDownloadBtnEnabled(boolean enabled) {
        downloadBtn.setEnabled(enabled);
    }

    /**
     * 设置下载按钮可见性
     */
    public void setDownloadBtnVisibility(int visibility) {
        downloadBtn.setVisibility(visibility);
    }

    /**
     * 获取下载按钮（供外部 measure 等操作使用）
     */
    public ImageButton getDownloadBtn() {
        return downloadBtn;
    }

    /**
     * 申请存储权限并保存录像到相册
     * Android 10+ 使用 MediaStore 不需要存储权限，直接保存
     * Android 9 及以下需要 WRITE_EXTERNAL_STORAGE 权限
     */
    public void requestStoragePermissionAndSave() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // Android 10+ 通过 MediaStore 保存不需要存储权限
            saveVideo2Album();
        } else {
            // Android 9 及以下需要写权限
            EZPermissionUtil.requestPermissions(mActivity,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    1000,
                    () -> saveVideo2Album()
            );
        }
    }

    /**
     * 将录像存储到相册
     */
    private void saveVideo2Album() {
        File file = new File(downloadFilePath);
        EZUtils.saveVideo2Album(mActivity, file, recordInfoDuration);
        if (mActivity.isMultiChannelDevice) {
            int index = downloadFilePath.lastIndexOf(".");
            String downloadFilePath2 = downloadFilePath.substring(0, index) + "_1" + downloadFilePath.substring(index);
            File file2 = new File(downloadFilePath2);
            EZUtils.saveVideo2Album(mActivity, file2, recordInfoDuration);
        }
        Utils.showToast(mActivity, mActivity.getResources().getString(R.string.already_saved_to_volume));
        // TODO downloadFilePath的录像可以自行删除，避免占用手机内存，可以在onDestroy的时候。不能立即调用file.delete();因为文件存储到相册是异步耗时操作。
    }

    // endregion

    // region --- 下载回调监听 ---

    /**
     * 下载回调监听
     */
    private class EZStreamDownloadCallback extends EZOpenSDKListener.EZStreamDownloadCallbackEx {

        private EZCloudRecordFile cloudFile;

        public EZStreamDownloadCallback() {
        }

        public EZStreamDownloadCallback(EZCloudRecordFile cloudFile) {
            this.cloudFile = cloudFile;
        }

        @Override
        public void onDownloadingSize(long downloadSize) {// 只有云存储录像支持下载进度回调，SD卡录像下载不支持
            if (cloudFile != null) {
                LogUtil.d(TAG, "percent--->" + downloadSize * 100 / cloudFile.getFileSize());
            }
        }

        @Override
        public void onSuccess(final String filepath) {
            if (mDownloadStartTime > 0) {
                long mDownloadStopTime = System.currentTimeMillis();
                Utils.showToast(mActivity, "下载成功，下载时长：" + (mDownloadStopTime - mDownloadStartTime)/1000 + " s");
                mDownloadStartTime = 0;
            }
            downloadFilePath = filepath;
            String successMsg = "saved video to " + filepath;
            LogUtil.d(TAG, successMsg);
            Utils.showToast(mActivity, successMsg);
            // 申请动态权限将下载文件存储到相册
            requestStoragePermissionAndSave();
        }

        @Override
        public void onError(final EZOpenSDKListener.EZStreamDownloadError code) {
            String failMsg = "failed: ";
            switch (code) {
                case ERROR_EZSTREAM_DOWNLOAD_MAX_CONNECTIONS:
                    failMsg += "device reached max connections!";
                    break;
                case ERROR_EZSTREAM_DOWNLOAD_VERIFYCODE:
                    failMsg += "The video has been encrypted, please enter the password!";
                    break;
                case ERROR_EZSTREAM_DOWNLOAD_START:
                    failMsg += "download parameter error or download startup failure, please check the log";
                    /**
                     * 下载启动失败可能有两个原因：
                     * 1、下载参数设置错误，请检查下载器参数设置是否错误
                     * 2、媒体类错误码，日志中搜索 handleDownloadError: 找到具体的错误码，再查阅错误码文档
                     *
                     * There may be two reasons for download startup failure:
                     * 1.Download parameter settings are incorrect. Please check if the downloader parameter settings
                     * are incorrect
                     * 2.Media related error codes, search for handleDownloadError:  in the log: find the specific
                     * error code,
                     *   and then refer to the error code document
                     */
                    break;
                default:
                    failMsg += code;
                    break;
            }
            Utils.showToast(mActivity, failMsg);
        }

        @Override
        public void onErrorCode(int code) {
            Utils.showToast(mActivity, R.string.download_fail, code);
        }

    }

    // endregion
}
