import httpClient from './core/httpClient'
import { Base64 } from '../node_modules/js-base64/base64';

/*
 *@description
 *@author  jsyang
 *@date  2021-06-03 14:55:19
 *@variable LoginUrl 登录接口
 *@variable 变量2
 *@variable 变量3
*/
export const STATUS_TYPE = {
    'LOGIN_SUCCESS': 'LoginSuccess',
    'LOGIN_ERROR': 'LoginError'
}
const LoginUrl = '/oauth/token'
export const serverName = '/video-platform-basedata'
// export const getAislesBySearchObjUrl = '/hik-stream/aisle-page'
export const getAislesUrl = '/hik-stream/aisle-page'
const getDefaultClientId = () => ['third', '-apli', 'cation'].join('')
const getDefaultClientSecret = () => [getDefaultClientId(), '2021'].join('')
export interface GlobalClientData {
    "access_token": string;
    "token_type": "bearer" | string;
    "refresh_token": string;
    "expires_in": number;
    "scope": "[server]" | string;
}
export class GlobalClientConfig {
    endPoint: string;
    username?: string;
    password?: string;
    appKey: string;
    appSecret:string;
    clientId?: string;
    clientSecret?: string;
    workerPath?: string;
    logoPath?: string;
}

/**
 * authClient
 * @param  参数1
 * @param  参数2
 * @return
 * @description
 * @author  jsyang
 * @date  2021-11-01 20:13:07
*/
export class GlobalClient {
    private _config: GlobalClientConfig;
    private _onStatusChanged
    private _data: GlobalClientData
    private _refreshTimer: ReturnType<typeof setTimeout> | null = null
    public get config() {
        return this._config
    }
    public set config(config) {
        this._config = { ...config }
    }
    private get data() {
        return this._data
    }
    private set data(data: GlobalClientData) {
        this._data = { ...data }
    }
    public get accessToken() {
        return this.data.access_token
    }

    constructor(config: GlobalClientConfig, onStatusChanged = (statusMsg) => { }) {
        this.config = { clientId: getDefaultClientId(), clientSecret: getDefaultClientSecret(), ...config, }
        this._onStatusChanged = onStatusChanged
        const username = config.appKey || config.username
        const password = config.appSecret || config.password
        this.login(config.endPoint + serverName + LoginUrl + '?grant_type=password&scope=server', { username, password }).then(res => {
            if (res.code === 0) {
                this.data = res.data
                this.scheduleRefresh(res.data.expires_in)
            } else {
                throw new Error(res);
            }
        }).then(() => {
            this._onStatusChanged(STATUS_TYPE.LOGIN_SUCCESS)
        }).catch(err => {
            this._onStatusChanged(STATUS_TYPE.LOGIN_ERROR, err)
        })
    }
    private login(url, body) {
        const { clientId, clientSecret } = this.config;
        return httpClient.post(url, body, {
            "Content-Type": "application/x-www-form-urlencoded",
            "Authorization": 'Basic ' + Base64.encode(`${clientId}:${clientSecret}`),
        })
    }
    private scheduleRefresh(expiresIn: number) {
        if (this._refreshTimer) {
            clearTimeout(this._refreshTimer)
        }
        // 提前 60 秒刷新，expiresIn 单位为秒
        const delay = Math.max((expiresIn - 60) * 1000, 0)
        this._refreshTimer = setTimeout(() => {
            this.refreshToken().catch(() => {
                // 刷新失败，尝试重新登录
                this.reLogin().catch(() => {})
            })
        }, delay)
    }
    async refreshToken() {
        const { config } = this
        const url = config.endPoint + serverName + LoginUrl + '?grant_type=refresh_token'
        return new Promise((resolve, reject) => {
            this.login(url, {
                refresh_token: this.data.refresh_token
            }).then(res => {
                if (res.code === 0) {
                    this.data = res.data
                    this.scheduleRefresh(res.data.expires_in)
                    resolve(res.data)
                } else {
                    reject(res)
                }
            }).catch(err => reject(err))
        })
    }
    async reLogin() {
        const { config } = this
        return new Promise((reslove, reject) => {
            const url = config.endPoint + serverName + LoginUrl + '?grant_type=password&scope=server'
            this.login(url, {
                username: this.config.appKey || this.config.username,
                password: this.config.appSecret || this.config.password
            }).then(res => {
                if (res.code === 0) {
                    this.data = res.data
                    this.scheduleRefresh(res.data.expires_in)
                    reslove(res.data)
                } else {
                    reject(res)
                }
            }).catch(err => {
                reject(err)
            })
        })
    }

    /*public getAislesBySearchObj(obj) {
        return new Promise((reslove, reject) => {
            if (!this.accessToken) {
                reject('无登录信息!')
            }
            const { config } = this;
            const url = config.endPoint + serverName + getAislesBySearchObjUrl
            httpClient.get(url, obj, {
                "Content-Type": "application/json;charset=UTF-8",
                "Authorization": 'Bearer ' + this.accessToken,
            }).then(res => {
                if (res.code === 0) {
                    reslove(res)
                } else {
                    reject(res)
                }
            }).catch(err => reject(err))
        })
    }*/

    public getAisles(params) {
        return new Promise((reslove, reject) => {
            if (!this.accessToken) {
                reject('无登录信息!')
            }
            const { config } = this;
            const url = config.endPoint + serverName + getAislesUrl
            httpClient.get(url, params, {
                "Content-Type": "application/json;charset=UTF-8",
                "Authorization": 'Bearer ' + this.accessToken,
            }).then(res => {
                if (res.code === 0) {
                    reslove(res)
                } else {
                    reject(res)
                }
            }).catch(err => reject(err))
        })
    }
    destroy() {
        if (this._refreshTimer) {
            clearTimeout(this._refreshTimer)
            this._refreshTimer = null
        }
    }
};

export default GlobalClient;
