/* eslint-disable */
import { v4 } from 'uuid'
import { SystemInfo, ShareMessage, HttpRequestConfig, Download } from './types'
import { urlScheme } from './constants'

declare global {
    interface Window {
        plus: any;
    }
}

interface AndroidErrorCallback {
    code: number;
    message: string;
}

export default new (class {
    private readonly plusready = new Promise<void>((resolve) => {
        if (this.hasPlus()) {
            resolve()
        } else {
            document.addEventListener('plusready', () => resolve())
        }
    })

    /**
     * 网络请求对象
     */
    private xhr = new XMLHttpRequest()

    /**
     * 当前下载进度任务
     */
    private progressTask = new Map()

    /**
     * 系统信息
     */
    private systemInfo: SystemInfo = {
        os: 'Web', // 客户端操作系统
        version: '1.0.0', // 客户端版本号
        versionCode: '100000', // 客户端版本代码
        statusBarHeight: 0, // 状态栏高度
    }

    constructor() {
        this.onPlusReady((plus) => {
            this.xhr = new plus.net.XMLHttpRequest()
            this.systemInfo.os = plus.os.name
            this.systemInfo.statusBarHeight = plus.navigator.getStatusbarHeight()

            plus.runtime.getProperty(plus.runtime.appid, (info: any) => {
                this.systemInfo.version = info.version
                this.systemInfo.versionCode = info.versionCode
            })
        })

        // 监听返回按钮事件
        this.onPlusReady((plus) => {
            let firstBack = true
            plus.key.addEventListener('backbutton', () => {
                const webviews = plus.webview.all() // 所有Webview窗口
                if (webviews.length > 1) {
                    plus.webview.close(webviews[webviews.length - 1])
                } else {
                    const webview = plus.webview.currentWebview()
                    webview.canBack((e: any) => {
                        // 判断能否继续返回
                        if (e.canBack) {
                            webview.back()
                        } else {
                            // 1秒内连续两次按返回键退出应用
                            if (firstBack) {
                                firstBack = false
                                plus.nativeUI.toast('再按一次退出应用')
                                setTimeout(() => {
                                    firstBack = true
                                }, 1000)
                            } else {
                                plus.runtime.quit()
                            }
                        }
                    })
                }
            })
        })
    }

    hasPlus() {
        return !!window.plus
    }

    onPlusReady(callback: (plus: Window['plus']) => void) {
        this.plusready.then(() => {
            callback(window.plus)
        })
    }

    /**
     * 退出应用程序
     */
    quit() {
        this.onPlusReady((plus) => {
            plus.runtime.quit()
        })
    }

    /**
     * 获取系统信息
     * @param prop 
     * @returns 
     */
    getSystemInfo<K extends keyof SystemInfo>(prop: K) {
        return this.systemInfo[prop]
    }

    /**
     * 获取状态栏高度
     * @param callback 
     */
    getStatusBarHeight(callback: (statusbarHeight: number) => void) {
        this.onPlusReady((plus) => {
            const height = plus.navigator.getStatusbarHeight()
            callback(height)
        })
    }

    /**
     * 设置状态栏文字颜色
     * @param color dark - 暗色，light - 亮色
     */
    setStatusBarStyle(color: 'dark' | 'light') {
        this.onPlusReady((plus) => {
            plus.navigator.setStatusBarStyle(color)
        })
    }

    /**
     * 隐藏状态栏
     */
    hideStatusBar() {
        this.onPlusReady((plus) => {
            plus.navigator.setFullscreen(true)
        })
    }

    /**
     * 显示状态栏
     */
    showStatusBar() {
        this.onPlusReady((plus) => {
            plus.navigator.setFullscreen(false)
        })
    }

    /**
     * 设置应用全屏
     */
    setFullSreen() {
        this.onPlusReady((plus) => {
            this.hideStatusBar()
            plus.navigator.hideSystemNavigation()
        })
    }

    /**
     * 应用退出全屏
     */
    exitFullSreen() {
        this.onPlusReady((plus) => {
            this.showStatusBar()
            plus.navigator.showSystemNavigation()
        })
    }

    /**
     * http 跨域请求(待完善)
     * @param config 
     * @returns 
     */
    httpRequest(config: HttpRequestConfig) {
        return new Promise<any>((resolve, reject) => {
            this.xhr.responseType = config.responseType ?? 'json'
            if (config.header) {
                for (const key in config.header) {
                    this.xhr.setRequestHeader(key, config.header[key])
                }
            }
            this.xhr.onreadystatechange = () => {
                if (this.xhr.readyState === 4) {
                    if (this.xhr.status == 200) {
                        resolve({
                            code: 200,
                            data: this.xhr.response
                        })
                    } else {
                        reject({
                            code: this.xhr.status,
                            message: this.xhr.statusText
                        })
                    }
                }
            }
            this.xhr.open(config.method ?? 'GET', config.url)
            this.xhr.send()
        })
    }

    /**
     * 删除文件
     * @param url 
     */
    deleteFile(url: string) {
        this.onPlusReady((plus) => {
            plus.io.resolveLocalFileSystemURL(url, (entry: any) => {
                entry.remove()
            })
        })
    }

    /**
     * 监听下载进度
     * @param callback 
     * @returns 
     */
    onDownloadProgress(callback: (progress: number) => void) {
        const uuid = v4()
        this.progressTask.set(uuid, callback)

        /** 注意离开页面时销毁监听事件，防止事件重复触发 */
        return {
            uuid,
            cancel: () => this.progressTask.delete(uuid)
        }
    }

    /**
     * 文件下载
     * https://www.html5plus.org/doc/zh_cn/downloader.html#plus.downloader.createDownload
     * @param url 
     */
    createDownload(url: string) {
        return new Promise<Download>((resolve, reject) => {
            this.onPlusReady((plus) => {
                // plus.downloader.enumerate((downloads: any) => {
                //     if (downloads.length) {
                //         plus.nativeUI.toast('正在下载')
                //     } else {

                //     }
                // })
                const task = plus.downloader.createDownload(url, {
                    filename: '_downloads/', // 非系统 Download 目录
                    retry: 1,
                }, (download: Download, status: number) => {
                    if (status === 200) {
                        resolve(download)
                    } else {
                        reject('下载失败，请稍后再试')
                    }
                    this.progressTask.clear()
                })
                // 监听下载状态
                task.addEventListener('statechanged', (e: Download) => {
                    //console.log(e.state, e.downloadedSize / e.totalSize * 100)
                    if (e.state === 3) {
                        const progress = e.downloadedSize / e.totalSize * 100
                        for (const fn of this.progressTask.values()) {
                            fn(progress) // 推送下载进度
                        }
                    }
                })
                // 开始下载
                task.start()
            })
        })
    }

    /**
     * App更新安装
     * @param file 
     */
    installApp(file: string) {
        this.onPlusReady((plus) => {
            plus.nativeUI.showWaiting('正在安装...')
            plus.runtime.install(file, {
                // true表示强制安装，不进行版本号的校验；false则需要版本号校验，如果将要安装应用的版本号不高于现有应用的版本号则终止安装，并返回安装失败。 仅安装wgt和wgtu时生效，默认值 false
                force: false
            }, () => {
                console.log('安装成功！')
                this.deleteFile(file)
                plus.nativeUI.closeWaiting()
                plus.runtime.restart()
            }, (e: any) => {
                plus.nativeUI.closeWaiting()
                plus.nativeUI.alert('安装失败：' + e.message)
            })
        })
    }

    /**
     * 保存图片到相册
     * @param base64Data 
     */
    saveImage(base64Data: string, fileName?: string) {
        this.onPlusReady((plus) => {
            const bitmap = new plus.nativeObj.Bitmap()
            const filename = fileName ?? new Date().getTime()
            bitmap.loadBase64Data(base64Data)
            bitmap.save(`_doc/${filename}.jpg`, { overwrite: true, quality: 100, }, (e: Event) => {
                //保存到系统相册
                plus.gallery.save(
                    e.target,
                    () => {
                        //销毁Bitmap图片
                        bitmap.clear()
                        plus.nativeUI.toast('已保存到相册中')
                    },
                    () => {
                        //销毁Bitmap图片
                        bitmap.clear()
                        plus.nativeUI.toast('保存失败')
                    }
                )
            }, (err: { message: string }) => {
                plus.nativeUI.toast(err.message)
            })
        })
    }

    /**
     * https://www.html5plus.org/doc/zh_cn/runtime.html#plus.runtime.openURL
     * @param url 
     */
    openURL(url: string) {
        if (this.hasPlus()) {
            this.onPlusReady((plus) => {
                plus.runtime.openURL(url)
            })
        } else {
            window.open(url)
        }
    }

    /**
     * https://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.create
     * @param options 
     */
    openWebview(options: { url: string; id?: string; titleText?: string; titleColor?: string; backgroundColor?: string; onClose?: () => void; }) {
        if (this.hasPlus()) {
            const styles = {
                titleNView: {
                    backgroundColor: options.backgroundColor,
                    titleText: options.titleText,
                    titleColor: options.titleColor,
                    autoBackButton: true,
                }
            }
            this.onPlusReady((plus) => {
                const wv = plus.webview.create(options.url, options.id ?? v4(), styles)
                wv.show()
                wv.addEventListener('close', () => options.onClose && options.onClose(), false)
            })
        } else {
            this.openURL(options.url)
        }
    }

    /**
     * 将本地URL路径转换成平台绝对路径
     * https://www.html5plus.org/doc/zh_cn/io.html#plus.io.convertLocalFileSystemURL
     * @param url 
     */
    convertLocalFileSystemURL(url: string) {
        return new Promise<string>((resolve) => {
            if (this.hasPlus()) {
                this.onPlusReady((plus) => {
                    const localURL = plus.io.convertLocalFileSystemURL('_www/' + url)
                    resolve(localURL)
                })
            } else {
                const absoluteURL = new URL(url, window.location.href).href
                resolve(absoluteURL)
            }
        })
    }

    /**
     * 读取本地文件内容
     * https://www.html5plus.org/doc/zh_cn/io.html#plus.io.resolveLocalFileSystemURL
     * @param filePath 
     * @returns 
     */
    getLocalFileContent(filePath: string) {
        return new Promise<any>((resolve, reject) => {
            this.onPlusReady((plus) => {
                plus.io.resolveLocalFileSystemURL('_www/' + filePath, (entry: any) => {
                    entry.file((file: any) => {
                        const fileReader = new plus.io.FileReader()
                        fileReader.readAsText(file, 'utf-8')
                        fileReader.onloadend = (evt: any) => {
                            resolve(evt.target.result)
                        }
                    })
                }, (e: any) => {
                    reject(e.message)
                })
            })
        })
    }

    /**
     * 系统分享
     * https://www.html5plus.org/doc/zh_cn/share.html#plus.share.sendWithSystem
     * @param message 
     * @returns 
     */
    systemShare(message: Partial<ShareMessage>) {
        return new Promise<void>((resolve, reject) => {
            this.onPlusReady((plus) => {
                const logo = plus.io.convertLocalFileSystemURL('./logo.gif')
                const shareMessage: Partial<ShareMessage> = {
                    type: 'web',
                    thumbs: ['file://' + logo],
                    ...message,
                }
                plus.share.sendWithSystem(shareMessage, () => {
                    resolve()
                }, (e: { code: number; message: string; }) => {
                    reject(e.message)
                })
            })
        })
    }

    /**
     * 内容分享
     * https://www.html5plus.org/doc/zh_cn/share.html#plus.share.getServices
     */
    share() {
        this.onPlusReady((plus) => {
            // 成功回调
            const success = (services: any) => {
                console.log('分享列表', services)
                services.forEach((e: any) => {
                    if (e.id === 'weixin') {
                        e.send({
                            type: 'web',
                            title: '标题',
                            content: '内容',
                            href: 'https://',
                        }, () => {
                            console.log('分享成功')
                        }, (e: Error) => {
                            console.log('分享失败', e.message)
                        })
                    }
                })
            }
            // 失败回调
            const error = (e: Error) => {
                console.log('获取分享列表失败', e.message)
            }
            plus.share.getServices(success, error)
        })
    }

    /**
     * 打开第三方APP
     * https://www.html5plus.org/doc/zh_cn/runtime.html#plus.runtime.launchApplication
     * @param app 
     */
    launchApplication<K extends keyof typeof urlScheme>(app: K) {
        this.onPlusReady((plus) => {
            const os = this.getSystemInfo('os')
            const params = Object.create(null)

            if (os === 'Android') {
                params.pname = urlScheme[app].pname
            }
            if (os === 'iOS') {
                params.action = urlScheme[app].scheme
            }

            plus.runtime.launchApplication(params, (e: Error) => {
                console.log('失败', e.message)
            })
        })
    }

    /**
     * 检查运行环境的权限
     * https://www.html5plus.org/doc/zh_cn/navigator.html#plus.navigator.checkPermission
     */
    checkPermission() {
        this.onPlusReady((plus) => {
            const res = plus.navigator.checkPermission('android.permission.READ_EXTERNAL_STORAGE')

            console.log(res)
        })
    }

    /**
     * 请求APP权限
     */
    requestPermission(options: Partial<{
        permissionId: string;
        errorMessage?: string;
        refuseMessage?: string;
        onSuccess?: () => void;
        onError?: (message: string) => void;
    }>) {
        const { onSuccess, onError } = options
        if (this.hasPlus()) {
            this.onPlusReady((plus) => {
                plus.android.requestPermissions([options.permissionId], (e: { granted: string[]; deniedPresent: string[]; deniedAlways: string[]; }) => {
                    if (e.deniedAlways.length > 0) {
                        onError && onError(options.refuseMessage ?? '')
                    }
                    if (e.deniedPresent.length > 0) {
                        onError && onError(options.errorMessage ?? '')
                    }
                    if (e.granted.length > 0) {
                        onSuccess && onSuccess()
                    }
                }, (e: AndroidErrorCallback) => {
                    onError && onError(e.message)
                })
            })
        } else {
            onSuccess && onSuccess()
        }
    }

    /**
     * 请求存储权限
     */
    requestPermissionReadExternalStorage(options: Partial<{ onSuccess: () => void; onError: (message: string) => void; }> = {}) {
        this.requestPermission({
            permissionId: 'android.permission.READ_EXTERNAL_STORAGE',
            errorMessage: '请打开存储权限',
            refuseMessage: '访问存储被拒绝',
            onSuccess: options.onSuccess,
            onError: options.onError
        })
    }

    /**
     * 请求摄像头权限
     */
    requestPermissionCamera(options: Partial<{ onSuccess: () => void; onError: (message: string) => void; }> = {}) {
        this.requestPermission({
            permissionId: 'android.permission.CAMERA',
            errorMessage: '请打开摄像头权限',
            refuseMessage: '访问摄像头被拒绝',
            onSuccess: options.onSuccess,
            onError: options.onError
        })
    }

    /**
     * 请求麦克风权限
     */
    requestPermissionRecordAudio(options: Partial<{ onSuccess: () => void; onError: (message: string) => void; }> = {}) {
        this.requestPermission({
            permissionId: 'android.permission.RECORD_AUDIO',
            errorMessage: '访问麦克风被拒绝',
            refuseMessage: '请打开麦克风权限',
            onSuccess: options.onSuccess,
            onError: options.onError
        })
    }
})