import { GLOBAL } from '@/static/Global.js';
import JsFn from '@/utils/js-fn.js';
import API from '@/api/index.js';
const blobPath = ['avatar', 'audio', 'doc', 'exam', 'image', 'item', 'notice', 'other', 'paper', 'syllabus', 'res', 'student', 'survey', 'temp', 'thum', 'video', 'vote', 'jyzx', 'train','yxpt']
const { BlobServiceClient, BlobClient } = require("@azure/storage-blob")
//获取文件后缀和类型
function getExAndType(fileName) {
    let ex = fileName.substring(fileName.lastIndexOf('.') + 1)
    let type = 'other'
    ex = ex.toUpperCase()
    for (let key in GLOBAL.CONTENT_TYPES) {
        if (GLOBAL.CONTENT_TYPES[key].indexOf(ex) != -1) {
            type = key
            break
        }
    }
    return {
        ex, type
    }
}

export default class BlobTool {
    /**
     * 初始化Blob,需要先调用授权API
     * @param {string} blobUrl blob地址
     * @param {string} container 容器名称
     * @param {string} sasString 授权 需要前面有 “ ? ”
     * @param {string} scope 学校(school)/个人(private) 计算空间大小
     * */
    constructor(blobUrl, container, sasString, scope) {
        this.initBlob(blobUrl, container, sasString, scope)
    }
    /**
     * 初始化Blob,需要先调用授权API
     * @param {string} blobUrl blob地址
     * @param {string} container 容器名称
     * @param {string} sasString 授权
     * @param {string} scope 学校(school)/个人(private) 计算空间大小
     * */
    initBlob(blobUrl, container, sasString, scope) {
        if (blobUrl && container && sasString && scope) {
            //初始化containerClient
            this.blobService = new BlobServiceClient(blobUrl + sasString)
            let containerClient = this.blobService.getContainerClient(container)
            if (containerClient) {
                this.containerClient = containerClient
                this.container = container
                this.blobUrl = blobUrl
                this.sasString = sasString
                this.scope = scope
                if (scope == 'private') {
                    let user_profile = localStorage.getItem('user_profile')
                    this.blobSpace = user_profile ? JSON.parse(decodeURIComponent(user_profile, "utf-8")).total : 0
                } else if (scope == 'school') {
                    let school_profile = localStorage.getItem('school_profile')
                    this.blobSpace = school_profile ? JSON.parse(decodeURIComponent(school_profile, "utf-8")).school_base.size : 0
                }
            } else {
                throw new Error("参数错误，初始化失败")
            }
        } else {
            throw new Error("初始化参数不完整")
        }
    }
    /**
     * 获取容器信息 (授权失败,需要账号级别的授权)
     * @param {object} 
     */
    getProperties(options) {
        return new Promise((r, j) => {
            //const blockBlobClient = this.containerClient.getBlockBlobClient('res/基础操作范例_16x9.HTE') //blob获取成功
            this.containerClient.getProperties(options).then(
                res => {
                    console.log('获取信息成功')
                    r(res)
                },
                err => {
                    console.log('获取信息失败')
                    j(err)
                }
            )
        })
    }

    /**
     * 上传文件方法,带回调上传进度
     * @param {any} file 文件对象
     * @param {any} path 文件夹路径 只需要文件夹名称 前后都不需要加‘/’
     * @param {any} option 官方可配置项
     * @param {any} checkSize 上传时是否检查容器空间 默认需要检查大小
     * @param {any} root path验证的根目录 默认为'/'
     * @returns {object} {url, name,size,createTime,extension,type}
     */
     upload(file, path, option = {}, checkSize = true,root = '/') {
        console.log(arguments)
		let checkPath = root === '/' ? path : path.replace(root,'')
		console.log(root);
		console.log(checkPath);
        if (!blobPath.includes(checkPath.split('/')[0])) {
            throw new Error('上传路径不合法，请检查上传路径：' + path)
        }
        return new Promise(async (r, j) => {
            //检查容器空间大小
            let isFull = false
            if (checkSize) {
                try {
                    isFull = await this.isContainerFull(this.scope)
                } catch (e) {
                    j({ spaceError: '容器空间计算失败，无法上传文件' })
                }
                if (isFull) {
                    j({ spaceError: 'Blob空间已满，无法上传' })
                }
            }
            const blockBlobClient = this.containerClient.getBlockBlobClient(path + "/" + file.name)
            blockBlobClient.uploadBrowserData(file, option).then(
                res => {
                    let url = decodeURIComponent(res._response.request.url)
                    url = url.substring(0, url.lastIndexOf('?'))
                    let info = getExAndType(file.name)
                    r({
                        url: url,
                        blob: '/' + path + "/" + file.name,
                        name: file.name,
                        size: res._response.request.body.size,
                        createTime: res.lastModified.getTime(),
                        extension: info.ex,
                        type: info.type
                    })
                },
                err => {
                    j(err)
                }
            )
        })
    }
    /**
     * 处理HTEX文件类型
     * @param {blobList} fileList 
     */
    handleHTEXFile(fileList) {
        let parseRes = []
        let names = []
        fileList.forEach((item, index) => {
            if (item.url.indexOf('/res/') > 0 && item.url.indexOf('.HTE') < 0) {
                let fileItem = {}
                let startIndex = JsFn.findChartIndex(item.blob, '/', 1)
                let endIndex = JsFn.findChartIndex(item.blob, '/', 2)
                let name = item.blob.substring(startIndex + 1, endIndex)
                let nameIndex = names.indexOf(name)
                if (nameIndex == -1) {
                    fileItem.url = this.blobUrl + '/' + this.container + '/res/' + name
                    fileItem.blob = `/res/${name}/index.json`
                    fileItem.name = name + '.HTEX'
                    fileItem.size = item.size
                    fileItem.createTime = item.createTime
                    fileItem.extension = 'HTEX'
                    fileItem.type = 'res'
                    names.push(name)
                    parseRes.push(fileItem)
                } else {
                    parseRes[nameIndex].size += item.size
                }
            } else {
                parseRes.push(item)
            }
        })
        return parseRes
    }

    /**
     * 列出所有（查询）
     * @param {Object} option ContainerListBlobsOptions
     * eg: option.prefix = 'res' 只查res文件夹下的blob
     * @returns {object} {blobList, continuationToken}
     */
    async listBlob(option, hendleHTEX = true) {
        return new Promise(async (r, j) => {
            let blobList = []
            if (this.containerClient) {
                let iter = this.containerClient.listBlobsFlat(option ? option : {});
                let blobItem = await iter.next();
                while (!blobItem.done) {
                    let blobName = blobItem.value.name
                    let info = getExAndType(blobItem.value.name)
                    blobList.push(
                        {
                            url: this.blobUrl + '/' + this.container + '/' + blobName,
                            blob: '/' + blobName,
                            // name: blobName.substring(JsFn.findChartIndex(blobName, '/', 0) + 1),
                            name: blobName.substring(blobName.lastIndexOf('/') + 1),
                            size: blobItem.value.properties.contentLength,
                            createTime: blobItem.value.properties.createdOn.getTime(),
                            extension: info.ex,
                            type: info.type
                        }
                    )
                    blobItem = await iter.next();
                }
                if (hendleHTEX) {
                    blobList = this.handleHTEXFile(blobList)
                }
                r({
                    blobList,
                    continuationToken: 'end'
                })
            } else {
                j('containerClient 错误')
            }
        })
    }
    /**
     * 分页列出（查询）
     * @param {Object} option ContainerListBlobsOptions
     * eg: option.prefix = 'res' 只查res文件夹下的blob
     * @param {Object} pageInfo 
     * eg: pageInfo.maxPageSize 当前请求条数
     * eg: pageInfo.continuationToken 首次请求不需要，后面需要（首次请求会返回，下次需要传入）
     * @returns {object} {blobList, continuationToken}
     */
    async listBlobByPage(option, pageInfo) {
        return new Promise(async (r, j) => {
            let page = {}
            let blobList = []
            if (pageInfo && JSON.stringify(pageInfo) != '{}') {
                page.maxPageSize = pageInfo.maxPageSize ? pageInfo.maxPageSize : 50
                if (pageInfo.continuationToken) {
                    page.continuationToken = pageInfo.continuationToken ? pageInfo.continuationToken : ''
                }
            }
            if (this.containerClient) {
                let iterator = this.containerClient.listBlobsFlat(option ? option : {}).byPage(page)
                let response = (await iterator.next()).value
                let prefixLen = response.prefix ? response.prefix.length + 1 : 0
                for (const blob of response.segment.blobItems) {
                    let info = getExAndType(blob.name)
                    blobList.push(
                        {
                            url: response.serviceEndpoint + response.containerName + '/' + blob.name,
                            blob: '/' + blob.name,
                            name: blob.name.substring(prefixLen),
                            size: blob.properties.contentLength,
                            createTime: blob.properties.lastModified.getTime(),
                            extension: info.ex,
                            type: info.type
                        }
                    )
                }
                let continuationToken = response.continuationToken ? response.continuationToken : 'end'
                r({
                    blobList,
                    continuationToken
                })
            } else {
                j('containerClient 错误')
            }
        })
    }
    /**
     * 删除Blob
     * @param {string} filePath 文件url + 容器 之后的路径
     */
    deleteBlob(filePath) {
        if (filePath) {
            filePath = filePath.substring(1)
            return new Promise((r, j) => {
                this.containerClient.deleteBlob(filePath).then(
                    async res => {
                        r(200)
                    },
                    err => {
                        j(err)
                    }
                )

            })
        } else {
            throw new Error("filePath参数错误")
        }
    }

    /**
     * 批量删除Blob 官方API授权失败(需要账号级别的授权,批量删除请访问后端API)
     * @param {string} files 文件url + 容器 之后的路径
     */
    deleteBlobs(files) {
        this.getProperties()
        let blobBatchClient = this.blobService.getBlobBatchClient()
        return new Promise((r, j) => {
            for (let i in files) {
                files[i] = files[i].substring(0, files[i].lastIndexOf('?'))
            }
            blobBatchClient.deleteBlobs(files, this.blobService.credential).then(
                res => {
                    console.log('批量删除成功')
                },
                err => {
                    console.log('批量删除失败')
                }
            )
        })
    }
    /**
     * 批量删除Blob 循环操作
     * @param {string} files 
     */
    deleteBlobBatch(files) {
        return new Promise((r, j) => {
            let promises = []
            for (let item of files) {
                let f = item.substring(1)
                promises.push(this.containerClient.deleteBlob(f))
            }
            Promise.all(promises).then(
                res => {
                    r(res)
                },
                err => {
                    j(err)
                }
            )
        })
    }
    /**
     * 复制单个Blob
     * @param {string} targetUrl 
     * @param {string} sourceUrl 
     * @param {string} sas 
     * 1、目标url（targetUrl）不需要完整路径，容器之后的相对路径
     * 2、源文件url（sourceUrl）1、完整路径（包括Host）； 2、如果需要授权的容器，则url需要凭借授权。
     */
    copyBlob(targetUrl, sourceUrl, sas) {
        return new Promise((r, j) => {
            console.log(...arguments)
            let newBlob = this.containerClient.getBlobClient(targetUrl)
            let encodeUrl = encodeURI(sourceUrl)
            newBlob.beginCopyFromURL(encodeUrl + sas).then(
                res => {
                    console.log('复制成功返回数据', res)
                    r(200)
                },
                err => {
                    j(500)
                }
            )
        })
    }

    /**
     * 复制‘文件夹’
     * @param {string} targetFolder eg:'exam/评测id/paper/8b94c6b6-2572-41e5-89b9-a82fcf13891e/' 注意开头不加‘/’, 结尾需要加‘/’
     * @param {string} sourceFolder eg:'paper/JEFF組卷測試01'
     * @param {BlobTool} blobTool 非必传参数， 当目标文件和源文件不在同一个容器的时候，需要传源文件容器初始化的BlobTool
     * @param {boolean} handleSize 是否内部处理blobsize
     */
    copyFolder(targetFolder, sourceFolder, blobTool, handleSize = true) {
		console.log(...arguments);
        return new Promise(async (r, j) => {
            try {
                let blobs = undefined
                let sasString = ''
                if (blobTool) {
                    blobs = await blobTool.listBlob({
                        prefix: sourceFolder + '/'
                    }, false)
                    sasString = blobTool.sasString
                } else {
                    blobs = await this.listBlob({
                        prefix: sourceFolder + '/'
                    }, false)
                    sasString = this.sasString
                }
                //上传之前检查文件夹大小
                let beforeSize = 0
                let cont = ''
                if (handleSize) {
                    cont = this.container
                }
                if (blobs && blobs.blobList.length) {
                    let count = 0
                    blobs.blobList.forEach(blobItem => {
                        let newUrl = targetFolder + blobItem.name
                        let newBlob = this.containerClient.getBlobClient(newUrl)
                        let resourceUrl = encodeURI(blobItem.url)
                        newBlob.beginCopyFromURL(resourceUrl + sasString).then(
                            async res => {
                                if (++count == (blobs.blobList.length)) {
                                    if (handleSize) {
                                        //复制之后更新大小
                                    }
                                    r(blobItem)
                                }
                            },
                            err => {
                                j('copy error')
                            }
                        )
                    })
                }else{
                    j('sourceFolder error or 404')
                }
            } catch {
                j('copy error')
            }

        })
    }
    /**
     * 判断文件是否存在
     * @param {string} filePath 文件路径 正确 'res/基础操作范例_16x9.HTE ' 错误 '/res/基础操作范例_16x9.HTE'
     * @param {object} 
     * return true/false
     */
    exists(filePath, options) {
        const blockBlobClient = this.containerClient.getBlockBlobClient(filePath)
        return new Promise((r, j) => {
            blockBlobClient.exists(options).then(
                res => {
                    r(res)
                },
                err => {
                    j(err)
                }
            )
        })
    }

    /**
     * 判断容器的空间是否已满
     * @params {containerName} 容器名称
     * @params {scope} 'school' or 'private'
     * return true/false
     */
    async isContainerFull(scope) {
        return new Promise(async (r, j) => {
            try {
                let sizeRes = await BlobTool.getContainerSize(this.container, scope)
                if (sizeRes) {
                    r(sizeRes.total > this.blobSpace * 1024 * 1024 * 1024)
                } else {
                    j('容器空间判断失败！')
                }
            } catch (e) {
                j('容器空间判断失败！')
            }

        })
    }

    /**
     * 新版获取blob空间大小
     * @params {containerName} 容器名称
     * @params {scope} 'school' or 'private'
     */
    static getContainerSize(containerName, scope) {
        if (containerName, scope) {
            return new Promise((r, j) => {
                API.blob.getContainerSize({
                    scope,
                    containerName
                }).then(
                    res => {
                        if (res) {
                            let contentSize = 0
                            let defined = ['image', 'res', 'video', 'audio', 'doc', 'other']
                            for (let key in res.catalog) {
                                if (defined.includes(key)) {
                                    contentSize += res.catalog[key]
                                }
                            }
                            res.catalog.appData = res.size - contentSize
                            res.catalog.total = res.size
                            res.catalog.teachSpace = res.teach //查询学校空间的时候，返回此学校已分配给教室的空间；查询个人容器返回为零，不需要处理
                            r(res.catalog)
                        } else {
                            j('API error')
                        }
                    },
                    err => {
                        j('API error')
                    }
                )
            })
        } else {
            throw new Error("参数不完整")
        }

    }

}
