import lodash from 'lodash';
import { BindAll } from 'lodash-decorators';
import { computed, toJS } from 'mobx';
import { lastValueFrom, Subject, zip } from 'rxjs';
import { AuthController, IAuthOptions } from './auth';
import env from './env';
import { InfoController } from './info';
import { AuthOptions } from './options';
declare global {
    interface Window {
        __MICRO_APP_ENVIRONMENT__: boolean;
        rawWindow: Window;
        /**
         * 挂载的顶层  PortalAuthController
         * @type {PortalAuthController}
         * @memberof Window
         */
        PortalAuth: PortalAuthController;
    }
}

export interface IPortalAuthOptions {
    /**
     * Portal  类型
     * @type {('General' | 'BP' | 'SP')}
     * @memberof IPortalAuthOptions
     */
    PortalType?: 'General' | 'BP' | 'SP'
    /**
     * Token 类型
     * @type {('JWT' | 'Other')}
     * @memberof IPortalAuthOptions
     */
    TokenType?: 'JWT' | 'Other'
    BPAuth?: IAuthOptions
    SPAuth?: IAuthOptions
}
/**
 * Portal 认证信息 BP&SP
 * @export
 * @class PortalAuthController
 */
@BindAll()
export class PortalAuthController {
    static get env() {
        return env
    }
    get env() {
        return env
    }
    /**
     * 存储的单列
     * @private
     * @static
     * @type {PortalAuthController}
     * @memberof PortalAuthController
     */
    protected static PortalAuth: PortalAuthController = undefined;
    /**
     * 混合认证
     * @protected
     * @static
     * @type {AuthController}
     * @memberof PortalAuthController
     */
    protected static GeneralAuth: AuthController = undefined;
    /**
     * BP 认证
     * @protected
     * @static
     * @type {AuthController}
     * @memberof PortalAuthController
     */
    protected static BPAuth: AuthController = undefined;
    /**
     * SP 认证
     * @protected
     * @static
     * @type {AuthController}
     * @memberof PortalAuthController
     */
    protected static SPAuth: AuthController = undefined;
    /**
     * 基础信息
     * @protected
     * @static
     * @type {InfoController}
     * @memberof PortalAuthController
     */
    protected static PortalInfo: InfoController = undefined;
    /**
     * 引流信息
     * @protected
     * @static
     * @type {InfoController}
     * @memberof PortalAuthController
     */
    protected static PortalDrainage: InfoController = undefined;
    protected static createAuth(options: IPortalAuthOptions) {
        switch (options.PortalType) {
            case 'BP':
                PortalAuthController.BPAuth = new AuthController({
                    CookieKey: ['BPPORTAL_TOKEN'],
                    StorageKey: 'BPPortal',
                    TokenType: options.TokenType || 'JWT'
                })
                return
            case 'SP':
                PortalAuthController.SPAuth = new AuthController({
                    CookieKey: ['SALES_TOKEN'],
                    StorageKey: 'SALESPortal',
                    TokenType: options.TokenType || 'Other'
                })
                return
            default:
                PortalAuthController.GeneralAuth = new AuthController({
                    CookieKey: ['BPPORTAL_TOKEN', 'SALES_TOKEN'],
                    StorageKey: 'Portal',
                    TokenType: options.TokenType || 'Other'
                })
        }
    };
    constructor(protected readonly options: IPortalAuthOptions = { PortalType: 'BP' }) {
        // 浏览器
        if (AuthOptions.browser) {
            // 微前端 环境中
            if (AuthOptions.micro && window?.rawWindow?.PortalAuth) {
                PortalAuthController.PortalAuth = window.rawWindow.PortalAuth
            } else if (window?.PortalAuth) {
                PortalAuthController.PortalAuth = window.PortalAuth
            }
            // 非微前端环境
            if (!AuthOptions.micro) {
                window.PortalAuth = this
            }
            // 单例
            if (PortalAuthController.PortalAuth) {
                return PortalAuthController.PortalAuth;
            }
        }
        PortalAuthController.createAuth(this.options);
        PortalAuthController.PortalInfo = new InfoController({ StorageKey: 'PortalInfo' });
        PortalAuthController.PortalDrainage = new InfoController({ StorageKey: 'PortalDrainage' });
        this.createHydrate();
        PortalAuthController.PortalAuth = this;
        AuthOptions.log('PortalAuth', this)
    }

    /**
     * 持久化初始化完成 Subject
     * @type {Promise<any>}
     * @memberof ControllerUser
     */
    protected readonly HydrateSubject = new Subject<Boolean>();
    /**
    * 持久化初始化完成 Promise
    * @type {Promise<any>}
    * @memberof ControllerUser
    */
    get HydrateAsync(): Promise<this> {
        return lastValueFrom(this.HydrateSubject, { defaultValue: undefined });
    }
    /**
     * 异步 HydrateSubject 已经完成
     * @readonly
     * @memberof PortalAuthController
     */
    get HydrateisStopped() {
        return this.HydrateSubject.isStopped
    }
    /**
     * BP Auth
     * @type {AuthController}
     * @memberof PortalAuthController
     */
    protected get BPAuth() {
        return PortalAuthController.BPAuth
    }
    /**
     * SP Auth
     * @type {AuthController}
     * @memberof PortalAuthController
     */
    protected get SPAuth() {
        return PortalAuthController.SPAuth
    }
    /**
     * 通用的 Auth
     * @type {AuthController}
     * @memberof PortalAuthController
     */
    protected get GeneralAuth() {
        return PortalAuthController.GeneralAuth
    }
    /**
     * 数据 Info
     * @readonly
     * @memberof PortalAuthController
     */
    protected get PortalInfo() {
        return PortalAuthController.PortalInfo
    }
    /**
     * 数据 引流
     * @readonly
     * @protected
     * @memberof PortalAuthController
     */
    protected get PortalDrainage() {
        return PortalAuthController.PortalDrainage
    }
    /** 
     * 基础数据
     * @readonly
     * @memberof PortalAuthController
     */
    @computed
    get Info() {
        return toJS(this.PortalInfo.value)
    }
    /**
     * 引流数据
     * @readonly
     * @memberof PortalAuthController
     */
    @computed
    get Drainage() {
        return toJS(this.PortalDrainage.value)
    }
    /**
     * AccessToken 返回校验 时间是否过期 过期 的 AccessToken 不返回
     * @readonly
     * @memberof PortalAuthController
     */
    @computed
    get AccessToken() {
        switch (this.options.PortalType) {
            case 'BP':
                return this.BPAuth.AccessToken
            case 'SP':
                return this.SPAuth.AccessToken
            default:
                return this.GeneralAuth.AccessToken
        }
    }
    /**
     * AccessToken 解码信息
     * @readonly
     * @memberof PortalAuthController
     */
    @computed
    get JwtDecoded() {
        switch (this.options.PortalType) {
            case 'BP':
                return this.BPAuth.JwtDecoded
            case 'SP':
                return this.SPAuth.JwtDecoded
            default:
                return this.GeneralAuth.JwtDecoded
        }
    }
    /**
     * 保存 AccessToken 校验有效性 无效过滤
     * @param {string} [AccessToken=undefined]
     * @memberof PortalAuthController
     */
    onSaveAccessToken(AccessToken: string = undefined, setCookie = false) {
        this.BPAuth?.onSaveAccessToken(AccessToken, setCookie)
        this.SPAuth?.onSaveAccessToken(AccessToken, setCookie)
        this.GeneralAuth?.onSaveAccessToken(AccessToken, setCookie)
    }
    /**
     * 存储info 信息
     * @param {*} value
     * @memberof PortalAuthController
     */
    onSaveInfo(value: any) {
        this.PortalInfo.onSave(value)
        AuthOptions.trace('Save Info', value)
    }
    /**
     * 存储 Drainage 信息
     * @param {*} value
     * @memberof PortalAuthController
     */
    onSaveDrainage(value: any) {
        this.PortalDrainage.onSave(value)
        AuthOptions.trace('Save Drainage', value)
    }
    /**
    * 清理所有的登录信息
    * @return {*} 
    * @memberof AuthController
    */
    async onClear() {
        try {
            AuthOptions.writeCheck()
            AuthOptions.trace('clear start')
            this.BPAuth?.onClear()
            this.SPAuth?.onClear()
            this.GeneralAuth?.onClear()
            this.PortalInfo?.onClear()
            this.PortalDrainage?.onClear()
            if (AuthOptions.browser) {
                window.localStorage?.clear()
                window.sessionStorage?.clear()
                await this.HydrateAsync
                await AuthOptions.LocalForage.clear();
            }
            AuthOptions.log('clear success', 'localStorage,sessionStorage,IndexedDB,cookie 全部清理')
        } catch (error) {
            AuthOptions.trace('clear error', error)
        }
    }
    /**
    * 创建持久化存储
    * @memberof BaseModel
    */
    protected async createHydrate() {
        try {
            const observables = lodash.compact([
                this.BPAuth?.HydrateAsync,
                this.SPAuth?.HydrateAsync,
                this.GeneralAuth?.HydrateAsync,
                this.PortalInfo?.HydrateAsync
            ])
            await lastValueFrom(zip(observables), { defaultValue: undefined })
            this.HydrateSubject.next(true)
            this.HydrateSubject.complete()
        } catch (error) {
            AuthOptions.trace('error', error)
            this.HydrateSubject.next(false)
            this.HydrateSubject.complete()
        }
    }
}
