/**
 * 文件系统相关接口
 */
/* globals GLOBAL_OBJECT */
import { callNative, getUid, emptyFn, typeCheck, callNativeSync, showSystemLog } from './util';
import compareVersion from '../lib/compareVersion';
import * as system from './system'
const {SDKVersion} = system.default.getSystemInfoSync();

function getParentDirectory(url){
    if(typeof url != 'string') {
        return url;
    }
    const DirName = url == '' ? '' : url.substring(0, url.lastIndexOf('/')); 
    const reg=new RegExp("%20","g");
    return DirName.replace(reg, " ");
}

function makesureDirectoryAccess(path) {
    const destPath = getParentDirectory(path);
    if(compareVersion(SDKVersion, '3.26.0') <= 0) {
        try {
            fileSystemManager.accessSync(destPath);
        } catch(e) {
            fileSystemManager.mkdirSync(destPath, true);
        }
    }
}

function throwErrorByCustomize(code, msg) {
    let error = new Error(msg);
    error.code = code;
    throw error;
}

/**
 * 描述文件状态的对象
 *
 * @class Stats
 */
class Stats {
    constructor({ mode, size, lastAccessedTime, lastModifiedTime, isDirectory, isFile }) {
        this.mode = mode;
        this.size = size;
        this.lastAccessedTime = lastAccessedTime;
        this.lastModifiedTime = lastModifiedTime;
        this._isDirectory = isDirectory;
        this._isFile = isFile;
    }

    isDirectory() {
        return this._isDirectory;
    }
    isFile() {
        return this._isFile;
    }
}

const btoa = (() => {
    const KEY_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    const polyfill = (input) => {
        let output = "";
        let chr1;
        let chr2;
        let chr3;
        let enc1;
        let enc2;
        let enc3;
        let enc4;
        let i = 0;

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output + KEY_STR.charAt(enc1) + KEY_STR.charAt(enc2) + KEY_STR.charAt(enc3) + KEY_STR.charAt(enc4);

        }

        return output;
    };

    try {
        if (window && window.btoa) {
            return window.btoa;
        }

        return polyfill;
    } catch (e) {
        return polyfill;
    }
})();

const atob = (() => {
    const KEY_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    const polyfill = (input) => {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        input = input.replace(/[^A-Za-z0-9+/=]/g, "");

        while (i < input.length) {

            enc1 = KEY_STR.indexOf(input.charAt(i++));
            enc2 = KEY_STR.indexOf(input.charAt(i++));
            enc3 = KEY_STR.indexOf(input.charAt(i++));
            enc4 = KEY_STR.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }

        }

        return output;
    };

    try {
        if (window && window.atob) {
            return window.atob;
        }

        return polyfill;
    } catch (e) {
        return polyfill;
    }
})();

/**
 * ArrayBuffer转Base64
 *
 * @param {ArrayBuffer} buffer
 * @returns {String}
 */
function transformArrayBufferToBase64(buffer) {
    var binary = '';
    var bytes = new Uint8Array(buffer);
    for (var len = bytes.byteLength, i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
    }

    return btoa(binary);
}

/**
 * Base64转ArrayBuffer
 *
 * @param {String} base64String
 * @returns {ArrayBuffer}
 */
function urlBase64ToArrayBuffer(base64String) {
    const padding = '='.repeat((4 - base64String.length % 4) % 4);
    const base64 = (base64String + padding)
        .replace(/-/g, '+')
        .replace(/_/g, '/');

    const output = atob(base64);

    const outputArray = new Uint8Array(output.length);

    for (let i = 0; i < output.length; ++i) {
        outputArray[i] = output.charCodeAt(i);
    }

    return outputArray.buffer;
}

const fileSystemManager = {
    /**
     * 判断文件/目录是否存在
     *
     * @param {Object} options
     * @param {String} options.path 要判断是否存在的文件/目录路径
     * @param {Function} options.success 成功回调
     * @param {Function} options.fail 失败回调
     */
    access(options = {}) {
        callNative('fs.access', options, { path: 'String' }, 'access');
    },
    accessSync(path) {
        const { code, msg } = callNativeSync('fs.accessSync', { path }, { path: 'String' }, 'accessSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }
    },
    /**
     * 在文件结尾追加内容
     *
     * @param {Object} options
     * @param {String} options.filePath 文件路径
     * @param {String|ArrayBuffer} options.data 追加的数据
     * @param {String} [options.encoding = 'utf8'] 字符编码
     * @param {Function} [options.success = emptyFn] 成功回调
     * @param {Function} [options.fail = emptyFn] 失败回调
     */
    appendFile({
        filePath,
        data,
        encoding = 'utf8',
        success = emptyFn,
        fail = emptyFn,
        complete = emptyFn,
    } = {}) {
        const callbackId = getUid();
        const successFn = typeof success === 'function' ? success : emptyFn;
        const failFn = typeof fail === 'function' ? fail : emptyFn;
        const completeFn = typeof complete === 'function' ? complete : emptyFn;
        const callbackFn = function(result) {
            if (result.code === 0) {
                successFn(Object.assign({ errMsg: 'appendFile:ok' }));
                completeFn(Object.assign({ errMsg: 'appendFile:ok' }));
            } else {
                failFn({ cerrMsg: result.msg });
                completeFn({ errMsg: result.msg });
            }
        };
        let options;

        if (data instanceof ArrayBuffer) {
            try {
                const base64Data = transformArrayBufferToBase64(data);
                options = {
                    filePath,
                    data: base64Data,
                    encoding: 'base64'
                };
            } catch (e) {
                failFn({ errMsg: `appendFile:fail ${e.message}` });
            }
        } else if (typeof data === 'string') {
            options = {
                filePath,
                data,
                encoding
            };
        }

        showSystemLog && console.log('------ callNative ------', 'appendFile', options);

        GLOBAL_OBJECT.callbacks[callbackId] = callbackFn;
        GLOBAL_OBJECT.callNative('fs.appendFile', JSON.stringify(options), callbackId);
    },
    appendFileSync(filePath, data, encoding = 'utf8') {
        let options;
        if (data instanceof ArrayBuffer) {
            try {
                const base64Data = transformArrayBufferToBase64(data);
                options = {
                    filePath,
                    data: base64Data,
                    encoding: 'base64'
                };
            } catch (e) {
                throwErrorByCustomize(e);
            }
        } else if (typeof data === 'string') {
            options = {
                filePath,
                data,
                encoding
            };
        }

        const { code, msg } = callNativeSync('fs.appendFileSync', options, { filePath: 'String', data: 'String', encoding: 'String' }, 'appendFileSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }
    },
    /**
     * 保存临时文件到本地。此接口会移动临时文件，因此调用成功后，tempFilePath 将不可用。
     *
     * @param {Object} options
     * @param {String} options.tempFilePath 临时文件路径
     * @param {String|null} [options.filePath=null] 存储的文件路径
     * @param {Function} [options.success = emptyFn] 成功回调
     * @param {Function} [options.fail = emptyFn] 失败回调
     */
    saveFile({
        tempFilePath,
        filePath = null,
        success = emptyFn,
        fail = emptyFn
    } = {}) {
        let failFn = typeof fail === 'function' ? fail : emptyFn;
        let result = typeCheck(filePath, 'String');

        if (result && result !== 'Null') {
            failFn({ errMsg: `saveFile:fail parameter error: parameter.filePath should be String instead of ${result}` });
            return;
        }

        const options = {
            tempFilePath,
            filePath,
            success,
            fail
        };
        makesureDirectoryAccess(options.filePath);
        callNative('fs.saveFile', options, { tempFilePath: 'String' }, 'saveFile');
    },
    saveFileSync(tempFilePath, filePath = null) {
        let result = typeCheck(filePath, 'String');

        if (result && result !== 'Null') {
            console.error(`saveFile:fail parameter error: parameter.filePath should be String instead of ${result}`);
            return;
        }
        makesureDirectoryAccess(filePath);
        const { code, msg, data } = callNativeSync('fs.saveFileSync', { tempFilePath, filePath }, { tempFilePath: 'String' }, 'saveFileSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }

        return data.savedFilePath;
    },
    /**
     * 获取该小程序下已保存的本地缓存文件列表
     *
     * @param {Object} options
     * @param {Function} options.success 成功回调
     * @param {Function} options.fail 失败回调
     */
    getSavedFileList(options = {}) {
        callNative('fs.getSavedFileList', options, {}, 'getSavedFileList');
    },
    /**
     * 删除该小程序下已保存的本地缓存文件
     *
     * @param {Object} options
     * @param {String} options.filePath 需要删除的文件路径
     * @param {Function} options.success 成功回调
     * @param {Function} options.fail 失败回调
     */
    removeSavedFile(options = {}) {
        callNative('fs.removeSavedFile', options, { filePath: 'String' }, 'removeSavedFile');
    },
    /**
     * 复制文件
     *
     * @param {Object} options
     * @param {String} options.srcPath 源文件
     * @param {String} options.destPath 目标文件
     * @param {Function} options.success 成功回调
     * @param {Function} options.fail 失败回调
     */
    copyFile(options = {}) {
        makesureDirectoryAccess(options.destPath);
        callNative('fs.copyFile', options, { srcPath: 'String', destPath: 'String' }, 'copyFile');
    },
    copyFileSync(srcPath, destPath) {
        makesureDirectoryAccess(destPath);
        const { code, msg } = callNativeSync('fs.copyFileSync', { srcPath, destPath }, { srcPath: 'String', destPath: 'String' }, 'copyFileSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }
    },
    /**
     * 获取该小程序下的 本地临时文件 或 本地缓存文件 信息
     *
     * @param {Object} options
     * @param {String} options.filePath 文件路径
     * @param {Function} options.success 成功回调
     * @param {Function} options.fail 失败回调
     */
    getFileInfo(options = {}) {
        callNative('fs.getFileInfo', options, { filePath: 'String' }, 'getFileInfo');
    },
    /**
     * 创建目录
     *
     * @param {Object} options
     * @param {String} options.dirPath 目录路径
     * @param {Boolean} options.recursive 是否递归
     * @param {Function} options.success 成功回调
     * @param {Function} options.fail 失败回调
     */
    mkdir({
        dirPath,
        recursive = false,
        success = emptyFn,
        fail = emptyFn
    } = {}) {
        const options = {
            dirPath,
            recursive: !!recursive,
            success,
            fail
        };
        if(compareVersion(SDKVersion, '3.26.0') <= 0) {
            options.recursive = true;
        }
        callNative('fs.mkdir', options, { dirPath: 'String' }, 'mkdir');
    },
    mkdirSync(dirPath, recursive = false) {
        if(compareVersion(SDKVersion, '3.26.0') <= 0) {
            recursive = true;
        }
        const { code, msg } = callNativeSync('fs.mkdirSync', { dirPath, recursive: !!recursive }, { dirPath: 'String' }, 'mkdirSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }
    },
    /**
     * 读取本地文件内容
     *
     * @param {Object} options
     * @param {String} options.filePath 文件路径
     * @param {String} [options.encoding = 'arraybuffer'] 编码
     * @param {Function} [options.success = emptyFn] 成功回调
     * @param {Function} [options.fail = emptyFn] 失败回调
     */
    readFile({
        filePath,
        encoding = 'arraybuffer',
        success = emptyFn,
        fail = emptyFn,
        complete = emptyFn
    } = {}) {
        showSystemLog && console.log('readFile', {filePath, encoding});
        const callbackId = getUid();
        const successFn = typeof success === 'function' ? success : emptyFn;
        const failFn = typeof fail === 'function' ? fail : emptyFn;
        const completeFn = typeof complete === 'function' ? complete : emptyFn;
        const callbackFn = (result) => {
            if (result.code === 0) {
                const key = result.data.key;
                const data = GLOBAL_OBJECT.callNative('_inner.getResult', JSON.stringify({ key }), '');

                if (encoding === 'arraybuffer') {
                    try {
                        const ab = urlBase64ToArrayBuffer(data);
                        successFn({ errMsg: 'readFile:ok', data: ab });
                        completeFn({ errMsg: 'readFile:ok', data: ab });
                    } catch (e) {
                        showSystemLog && console.log('readFile parse error', e);
                        failFn({ errMsg: `readFile:fail ${e.message}` });
                        completeFn({ errMsg: `readFile:fail ${e.message}` });
                    }
                } else {
                    successFn({ errMsg: 'readFile:ok', data: data });
                    completeFn({ errMsg: 'readFile:ok', data: data });
                }
            } else {
                failFn({ errMsg: result.msg });
                completeFn({ errMsg: result.msg });
            }
        };

        let result = typeCheck(filePath, 'String');
        if (result) {
            failFn({ errMsg: `readFile:fail parameter error: parameter.filePath should be String instead of ${result}` });
            completeFn({ errMsg: `readFile:fail parameter error: parameter.filePath should be String instead of ${result}` });
            return;
        }

        result = typeCheck(encoding, 'String');
        if (result) {
            failFn({ errMsg: `readFile:fail parameter error: parameter.encoding should be String instead of ${result}` });
            completeFn({ errMsg: `readFile:fail parameter error: parameter.encoding should be String instead of ${result}` });
            return;
        }

        encoding = encoding || 'arraybuffer';

        GLOBAL_OBJECT.callbacks[callbackId] = callbackFn;
        GLOBAL_OBJECT.callNative('fs.readFile', JSON.stringify({ filePath, encoding: encoding === 'arraybuffer' ? 'base64' : encoding }), callbackId);
    },
    readFileSync(filePath, encoding = 'arraybuffer') {
        const { code, msg, data } = callNativeSync('fs.readFileSync', { filePath, encoding: encoding === 'arraybuffer' ? 'base64' : encoding }, { filePath: 'String', encoding: 'String' }, 'readFileSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }

        if (encoding === 'arraybuffer') {
            try {
                return urlBase64ToArrayBuffer(data.data);
            } catch (e) {
                throwErrorByCustomize(e);
            }
        }

        return data.data;
    },
    /**
     * 读取目录内文件列表
     *
     * @param {Object} options
     * @param {String} options.dirPath 目录路径
     * @param {Function} options.success 成功回调
     * @param {Function} options.fail 失败回调
     */
    readdir(options = {}) {
        callNative('fs.readdir', options, { dirPath: 'String' }, 'readdir');
    },
    readdirSync(dirPath) {
        const { code, msg, data } = callNativeSync('fs.readdirSync', { dirPath }, { dirPath: 'String' }, 'readdirSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }

        return data && data.files || data;
    },
    /**
     * 重命名文件。可以把文件从 oldPath 移动到 newPath
     *
     * @param {Object} options
     * @param {String} options.oldPath 源文件
     * @param {String} options.newPath 目标文件
     * @param {Function} options.success 成功回调
     * @param {Function} options.fail 失败回调
     */
    rename(options = {}) {
        makesureDirectoryAccess(options.newPath);
        callNative('fs.rename', options, { oldPath: 'String', newPath: 'String' }, 'rename');
    },
    renameSync(oldPath, newPath) {
        makesureDirectoryAccess(newPath);
        const { code, msg } = callNativeSync('fs.renameSync', { oldPath, newPath }, { oldPath: 'String', newPath: 'String' }, 'renameSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }
    },
    /**
     * 删除目录
     *
     * @param {Object} options
     * @param {String} options.dirPath 目录路径
     * @param {Boolean} [options.recursive = false] 是否递归
     * @param {Function} [options.success = emptyFn] 成功回调
     * @param {Function} [options.fail = emptyFn] 失败回调
     */
    rmdir({
        dirPath,
        recursive = false,
        success = emptyFn,
        fail = emptyFn
    } = {}) {
        const options = {
            dirPath,
            recursive,
            success,
            fail
        };

        callNative('fs.rmdir', options, { dirPath: 'String', recursive: 'Boolean' }, 'rmdir');
    },
    rmdirSync(dirPath, recursive = false) {
        const { code, msg } = callNativeSync('fs.rmdirSync', { dirPath, recursive: !!recursive }, { dirPath: 'String' }, 'rmdirSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }
    },
    /**
     * 获取文件 Stats 对象
     *
     * @param {Object} options
     * @param {String} options.path 目录路径
     * @param {Boolean} [options.recursive = false] 是否递归
     * @param {Function} [options.success = emptyFn] 成功回调
     * @param {Function} [options.fail = emptyFn] 失败回调
     */
    stat({
        path,
        recursive = false,
        success = emptyFn,
        fail = emptyFn,
        complete = emptyFn
    } = {}) {
        const callbackId = getUid();
        const successFn = typeof success === 'function' ? success : emptyFn;
        const failFn = typeof fail === 'function' ? fail : emptyFn;
        const completeFn = typeof complete === 'function' ? complete : emptyFn;
        const callbackFn = (result) => {
            if (result.code === 0) {
                if (recursive && Array.isArray(result.data.stats)) {
                    successFn({
                        errMsg: 'stat:ok',
                        stats: result.data.stats.map(({ path, stats }) => {
                            return { path, stats: new Stats(stats) };
                        })
                    });
                    completeFn({
                        errMsg: 'stat:ok',
                        stats: result.data.stats.map(({ path, stats }) => {
                            return { path, stats: new Stats(stats) };
                        })
                    });
                } else {
                    successFn({ errMsg: 'stat:ok', stats: new Stats(result.data.stats) });
                    completeFn({ errMsg: 'stat:ok', stats: new Stats(result.data.stats) });
                }
            } else {
                failFn({ errMsg: result.msg });
                completeFn({ errMsg: result.msg });
            }
        };
        let result = typeCheck(path, 'String');
        if (result) {
            failFn({ errMsg: `stat:fail parameter error: parameter.path should be String instead of ${result}` });
            completeFn({ errMsg: `stat:fail parameter error: parameter.path should be String instead of ${result}` });
            return;
        }

        result = typeCheck(recursive, 'Boolean');
        if (result) {
            failFn({ errMsg: `stat:fail parameter error: parameter.recursive should be String instead of ${result}` });
            completeFn({ errMsg: `stat:fail parameter error: parameter.recursive should be String instead of ${result}` });
            return;
        }

        const options = {
            path,
            recursive
        };

        GLOBAL_OBJECT.callbacks[callbackId] = callbackFn;
        GLOBAL_OBJECT.callNative('fs.stat', JSON.stringify(options), callbackId);
    },
    statSync(path, recursive = false) {
        const { code, msg, data } = callNativeSync('fs.statSync', { path, recursive: !!recursive }, { path: 'String' }, 'statSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }

        if (recursive && Array.isArray(data.stats)) {
            return data.stats.map(({ path, stats }) => {
                return { path, stats: new Stats(stats) };
            });
        }

        return new Stats(data.stats);
    },
    /**
     * 删除文件
     *
     * @param {Object} options
     * @param {String} options.filePath 文件路径
     * @param {Function} options.success 成功回调
     * @param {Function} options.fail 失败回调
     */
    unlink(options = {}) {
        callNative('fs.unlink', options, { filePath: 'String' }, 'unlink');
    },
    unlinkSync(filePath) {
        const { code, msg } = callNativeSync('fs.unlinkSync', { filePath }, { filePath: 'String' }, 'unlinkSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }
    },
    /**
     * 解压文件
     *
     * @param {Object} options
     * @param {String} options.zipFilePath zip文件路径
     * @param {String} options.targetPath 目标目录路径
     * @param {Function} options.success 成功回调
     * @param {Function} options.fail 失败回调
     */
    unzip(options = {}) {
        callNative('fs.unzip', options, { zipFilePath: 'String', targetPath: 'String' }, 'unzip');
    },
    /**
     * 写文件
     *
     * @param {Object} options
     * @param {String} options.filePath 文件路径
     * @param {String|ArrayBuffer} options.data 写入内容
     * @param {String} [options.encoding = 'utf8'] 编码
     * @param {Function} [options.success = emptyFn] 成功回调
     * @param {Function} [options.fail = emptyFn] 失败回调
     */
    writeFile({
        filePath,
        data,
        encoding = 'utf8',
        success = emptyFn,
        fail = emptyFn,
        complete = emptyFn,
    } = {}) {
        const callbackId = getUid();
        const successFn = typeof success === 'function' ? success : emptyFn;
        const failFn = typeof fail === 'function' ? fail : emptyFn;
        const completeFn = typeof complete === 'function' ? complete : emptyFn;
        const callbackFn = function(result) {
            if (result.code === 0) {
                successFn({ errMsg: 'writeFile:ok' });
                completeFn({ errMsg: 'writeFile:ok' });
            } else {
                failFn({ errMsg: result.msg });
                completeFn({ errMsg: result.msg });
            }
        };
        let result = typeCheck(filePath, 'String');
        if (result) {
            failFn({ errMsg: `writeFile:fail parameter error: parameter.filePath should be String instead of ${result}` });
            completeFn({ errMsg: `writeFile:fail parameter error: parameter.filePath should be String instead of ${result}` });
            return;
        }

        result = typeCheck(data, 'String');
        if (result && !(data instanceof ArrayBuffer)) {
            failFn({ errMsg: `writeFile:fail parameter error: parameter.data should be String or ArrayBuffer instead of ${result}` });
            completeFn({ errMsg: `writeFile:fail parameter error: parameter.data should be String or ArrayBuffer instead of ${result}` });
            return;
        }

        result = typeCheck(encoding, 'String');
        if (result) {
            failFn({ errMsg: `writeFile:fail parameter error: parameter.encoding should be String instead of ${result}` });
            completeFn({ errMsg: `writeFile:fail parameter error: parameter.encoding should be String instead of ${result}` });
            return;
        }

        let options;

        if (data instanceof ArrayBuffer) {
            const base64Data = transformArrayBufferToBase64(data);
            options = {
                filePath,
                data: base64Data,
                encoding: 'base64'
            };
        } else if (typeof data === 'string') {
            options = {
                filePath,
                data,
                encoding
            };
        }
        makesureDirectoryAccess(options.filePath);
        GLOBAL_OBJECT.callbacks[callbackId] = callbackFn;
        GLOBAL_OBJECT.callNative('fs.writeFile', JSON.stringify(options), callbackId);
    },
    writeFileSync(filePath, data, encoding = 'utf8') {
        let options;
        if (data instanceof ArrayBuffer) {
            const base64Data = transformArrayBufferToBase64(data);
            options = {
                filePath,
                data: base64Data,
                encoding: 'base64'
            };
        } else if (typeof data === 'string') {
            options = {
                filePath,
                data,
                encoding
            };
        }
        makesureDirectoryAccess(options.filePath);
        const { code, msg } = callNativeSync('fs.writeFileSync', options, { filePath: 'String', data: 'String', encoding: 'String' }, 'writeFileSync');

        if (code !== 0) {
            // throwErrorByCustomize(msg);
            throwErrorByCustomize(code, msg);
        }
    }
};

export default {
    /**
     * 获取全局唯一的FileSystemManager
     *
     * @returns
     */
    getFileSystemManager() {
        return fileSystemManager;
    },
    // bl下额外挂一个saveFile接口与微信对齐
    saveFile: fileSystemManager.saveFile,
    openDocument(options = {
        filePath: '',
        fileType: ''
    }) {
        // const successFn = typeof options.success === 'function' ? options.success : ()=>{};
        const failFn = typeof options.fail === 'function' ? options.fail : ()=>{};
        const completeFn = typeof options.complete === 'function' ? options.complete : ()=>{};
        const fileArray = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf'];
        let checkRes = true;

        // 校验必填项
        if (typeof options.filePath === 'string' && !/^blfile.+/.test(options.filePath)) {
            checkRes = false;
            failFn({
                errMsg: "openDocument:fail file not exist"
            });
            completeFn({
                errMsg: "openDocument:fail file not exist"
            });
        } else {
            if (!options.fileType) {
                if (!/\.(doc|docx|xls|xlsx|ppt|pptx|pdf)/.test(options.filePath)) {
                    checkRes = false;
                    failFn({
                        errMsg: "openDocument:fail fileType not supported"
                    });
                    completeFn({
                        errMsg: "openDocument:fail fileType not supported"
                    });
                }
            } else {
                if (fileArray.indexOf(options.fileType.toString()) === -1) {
                    checkRes = false;
                    failFn({
                        errMsg: "openDocument:fail fileType not supported"
                    });
                    completeFn({
                        errMsg: "openDocument:fail fileType not supported"
                    });
                }
            }
        }

        if (checkRes) {
            callNative('openDocument', options, {filePath: 'String'}, 'openDocument');
        }
    }
};

export const readFile = fileSystemManager.readFile;
