var util = require("thinkjs-util");
var request = require("requestretry");
var fs = require("fs");
var path = require("path");

module.exports = util.Class(function() {
    return {
        /**
         * 默认接口域名
         * @type {String}
         */
        DEFAULT_DOMAIN: "v0.api.upyun.com",
        /**
         * 接口的域名
         * @type {String}
         */
        domain: this.DEFAULT_DOMAIN,
        /**
         * 初始化
         * @param  {[type]} bucketname [description]
         * @param  {[type]} username   [description]
         * @param  {[type]} password   [description]
         * @return {[type]}            [description]
         */
        init: function(bucketname, username, password) {
            this.bucketname = bucketname;
            this.username = username;
            this.password = util.md5(password);
            this.domain = this.DEFAULT_DOMAIN;
        },
        /**
         * 设置接口的domain
         * @param {[type]} domain [description]
         */
        setDomain: function(domain) {
            this.domain = domain;
            return this;
        },
        /**
         * 签名
         * @param  {[type]} method [description]
         * @param  {[type]} uri    [description]
         * @param  {[type]} date   [description]
         * @param  {[type]} length [description]
         * @return {[type]}        [description]
         */
        sign: function(method, uri, date, length) {
            var sign = method + '&' + uri + '&' + date + '&' + length + '&' + this.password;
            return 'UpYun ' + this.username + ':' + util.md5(sign);
        },
        /**
         * 获取文件或者文件夹的信息
         * @param  {[type]} file [description]
         * @return {[type]}      [description]
         */
        getInfo: function(file) {
            return this.request(file, 'HEAD').then(function(response) {
                var headers = response.headers;
                return {
                    type: headers['x-upyun-file-type'],
                    size: headers['x-upyun-file-size'],
                    date: headers['x-upyun-file-date']
                };
            });
        },
        /**
         * 查看空间占用信息
         * @return {[type]} [description]
         */
        getUsage: function(path) {
            path = path || "/";
            return this.request(path + "?usage").then(function(response) {
                return parseInt(response.body, 10);
            });
        },
        /**
         * 从返回的headers里获取图片的信息
         * @param  {[type]} response [description]
         * @return {[type]}          [description]
         */
        getPicInfo: function(response) {
            var headers = response.headers;
            return {
                width: headers['x-upyun-width'],
                height: headers['x-upyun-height'],
                frames: headers['x-upyun-frames'],
                type: headers['x-upyun-file-type']
            };
        },
        /**
         * 上传文件或者文件夹
         * @param  {[type]} savePath [description]
         * @param  {[type]} filePath [description]
         * @return {[type]}          [description]
         */
        upload: function(savePath, filePath, headers) {
            var defaultHeaders = {
                mkdir: true
            };
            if (util.isObject(headers)) {
                defaultHeaders = util.extend(defaultHeaders, headers);
            } else if (headers) {
                defaultHeaders["Content-Secret"] = headers;
            }
            var self = this;
            //文件上传
            if (util.isFile(filePath)) {
                var stream = fs.readFileSync(filePath);
                var filename;
                if (!(/\.\w+$/.test(savePath))) {
                    filename = filePath.split('/');
                    filename = filename[filename.length - 1];
                    savePath += '/' + filename;
                }
                return this.request(savePath, 'PUT', stream, defaultHeaders).then(function(response) {
                    return self.getPicInfo(response);
                }).then(function(data) {
                    if (filename) {
                        data.filename = filename;
                    }
                    return data;
                });
            } else if (util.isDir(filePath)) { //文件夹上传
                if (savePath.slice(-1) !== '/') {
                    savePath += '/';
                }
                if (filePath.slice(-1) !== '/') {
                    filePath += '/';
                }
                var promises = [];
                var files = fs.readdirSync(filePath);
                files.forEach(function(item) {
                    var nFilePath = filePath + item;
                    var state = fs.statSync(nFilePath);
                    if (state.isFile() || state.isDirectory()) {
                        var promise = self.upload(savePath + item, nFilePath);
                        promises.push(promise);
                    }
                });
                if (promises.length) {
                    return util.Promise.all(promises);
                } else {
                    return self.mkDir(savePath);
                }
            } else { //普通内容上传
                return this.request(savePath, 'PUT', filePath, defaultHeaders).then(function(response) {
                    return self.getPicInfo(response);
                });
            }
        },
        /**
         * 文件或者文件夹下载
         * @param  {[type]} path     [description]
         * @param  {[type]} savePath [description]
         * @return {[type]}          [description]
         */
        download: function(sourcePath, savePath, typeData) {
            sourcePath = sourcePath || "/";
            //if (savePath && savePath.slice(-1) !== "/") {
            //	savePath += "/";
            //}
            var self = this;
            var promise = typeData ? util.getPromise(typeData) : this.getInfo(sourcePath);
            return promise.then(function(data) {
                if (data.type === 'folder') {
                    if (sourcePath.slice(-1) !== "/") {
                        sourcePath += "/";
                    }
                    return self.readDir(sourcePath).then(function(data) {
                        var promises = [];
                        data.forEach(function(item) {
                            var nPath = sourcePath + item.name;
                            var promise;
                            //文件夹
                            if (item.type === 'F') {
                                promise = self.download(nPath + "/", savePath + item.name + "/", {
                                    type: 'folder'
                                });
                            } else if (item.type) { //文件
                                promise = self.download(nPath, savePath, {
                                    type: 'file'
                                });
                            }
                            promises.push(promise);
                        });
                        return util.Promise.all(promises);
                    });
                } else {
                    //单个文件
                    return self.request(sourcePath, 'GET', '', {}, {
                        encoding: null
                    }).then(function(response) {
                        if (!savePath) {
                            return response.body;
                        }
                        var sourceExt = path.extname(sourcePath);
                        var saveExt = path.extname(savePath);
                        var fileSavePath = savePath;
                        if (sourceExt && sourceExt === saveExt) {
                            util.mkdir(path.dirname(savePath));
                        } else {
                            util.mkdir(savePath);
                            fileSavePath = savePath + path.basename(sourcePath);
                        }
                        fs.writeFileSync(fileSavePath, response.body);
                    });
                }
            });
        },
        /**
         * 删除文件或者文件夹
         * @param  {[type]} path  [description]
         * @param  {[type]} force [description]
         * @return {[type]}       [description]
         */
        rm: function(path, force) {
            if (!path) {
                return util.getPromise(new Error("path can't empty"), true);
            }
            if (path.slice(-1) !== '/') {
                path += '/';
            }
            var self = this;
            return this.getInfo(path).then(function(data) {
                if (data.type === 'folder') {
                    if (!force) {
                        return self.request(path, 'DELETE').then(function(response) {
                            return response.body;
                        });
                    }
                    return self.readDir(path).then(function(data) {
                        var promises = [];
                        data.forEach(function(item) {
                            var nPath = path + item.name;
                            var promise;
                            //文件夹
                            if (item.type === 'F') {
                                promise = self.rm(nPath + "/", true);
                            } else if (item.type) { //文件
                                promise = self.rm(nPath);
                            }
                            promises.push(promise);
                        });
                        if (promises.length) {
                            return util.Promise.all(promises);
                        }
                    }).then(function() {
                        return self.rm(path, false);
                    });
                } else {
                    return self.request(path, 'DELETE').then(function(response) {
                        return response.body;
                    });
                }
            });
        },
        /**
         * 递归创建目录
         * @param  {[type]} path [description]
         * @return {[type]}      [description]
         */
        mkDir: function(path) {
            return this.request(path, 'PUT', '', {
                mkdir: true,
                folder: true
            }).then(function(response) {
                return response.body;
            });
        },
        /**
         * 读取目录下的文件和子目录
         * @param  {[type]} dir [description]
         * @return {[type]}     [description]
         */
        readDir: function(path, recursive) {
            path = path || "/";
            if (path.slice(-1) !== '/') {
                path += '/';
            }
            var self = this;
            return this.request(path, "GET").then(function(response) {
                var dirs = response.body.split("\n");
                var result = [];
                var promises = [];
                for (var i = 0; i < dirs.length; i++) {
                    var dir = dirs[i];
                    var attrs = dir.split("\t");
                    dir = {
                        name: attrs[0],
                        type: attrs[1],
                        size: attrs[2],
                        time: attrs[3]
                    };
                    if (recursive && dir.type === 'F') {
                        var promise = self.readDir(path + dir.name, true).then(function(data) {
                            dir.children = data;
                        });
                        promises.push(promise);
                    }
                    result.push(dir);
                }
                if (promises.length) {
                    return util.Promise.all(promises).then(function() {
                        return result;
                    });
                } else {
                    return result;
                }
            });
        },
        /**
         * 请求数据
         * @param  {[type]} uri     [description]
         * @param  {[type]} method  [description]
         * @param  {[type]} data    [description]
         * @param  {[type]} headers [description]
         * @param  {[type]} options [description]
         * @return {[type]}         [description]
         */
        request: function(uri, method, data, headers, options) {
            uri = "/" + this.bucketname + uri;
            method = method || "GET";
            headers = headers || {};
            var length = 0;
            if (data) {
                length = !util.isBuffer(data) ? Buffer.byteLength(data) : data.length;
            }
            var date = (new Date()).toUTCString();
            var Authorization = this.sign(method, uri, date, length);
            headers = util.extend(headers, {
                'Content-Length': length,
                'Date': date,
                'Authorization': Authorization
            });
            var deferred = util.getDefer();
            var url = '';
            if (this.domain == this.DEFAULT_DOMAIN) {
                url = "https://" + this.domain + uri;
            } else {
                url = "http://" + this.domain + uri;
            }
            var opts = util.extend({
                url: url,
                method: method,
                body: data || "",
                timeout: 120000,
                headers: headers,
                maxAttempts: 5,
                retryDelay: 1000,
                retryStrategy: request.RetryStrategies.HTTPOrNetworkError
            }, options);
            request(opts, function(error, response, body) {
                if (error || response == undefined || response.statusCode !== 200) {
                    deferred.reject({
                        code: (response && response.statusCode) ? response.statusCode : -1,
                        message: error || "statusCode: " + response.statusCode + "; body: " + body
                    });
                } else {
                    deferred.resolve(response);
                }
            });
            return deferred.promise;
        }
    };
});