import qs from 'qs';
import { GlobalHelp, IPSAppResource, IPSAppView } from '@ibiz/dynamic-model-api';
import { clearCookie, getCookie, SyncSeriesHook } from 'qx-util';
import { AppServiceBase, Http, getSessionStorage, setSessionStorage, AppModelService, Util, GetModelService, ViewTool, LogUtil, IParams } from 'ibiz-core';
import { AppCenterService, AppNoticeService, AppViewLogicService, NoticeHandler } from 'ibiz-vue';
import { Environment } from '@/environments/environment';
import i18n from '@/locale';
import { MicroAppService } from '@/micro';
import { handleLocaleMap } from '@/locale/local-util';
import { AppComponentService } from '../service/app-component-service';
import { AppNoAuthDataService } from '../service/app-no-auth-data-service';

/**
 * AuthGuard net 对象
 * 调用 getInstance() 获取实例
 *
 * @class Http
 */
export class AuthGuard {


    /**
     * 执行钩子(包含获取租户前、获取租户后、获取应用数据前、获取应用数据后)
     *
     * @memberof AuthGuard
     */
    public static hooks = {
        dcSystemBefore: new SyncSeriesHook<[], { dcsystem: string }>(),
        dcSystemAfter: new SyncSeriesHook<[], { dcsystem: string, data: any }>(),
        appBefore: new SyncSeriesHook<[], { url: string, param: any }>(),
        appAfter: new SyncSeriesHook<[], { data: any }>()
    };

    /**
     * 获取 Auth 单例对象
     *
     * @static
     * @returns {AuthGuard}
     * @memberof AuthGuard
     */
    static getInstance(): AuthGuard {
        if (!AuthGuard.auth) {
            AuthGuard.auth = new AuthGuard();
        }
        return this.auth;
    }

    /**
     * 单例变量声明
     *
     * @private
     * @static
     * @type {AuthGuard}
     * @memberof AuthGuard
     */
    private static auth: AuthGuard;

    /**
     * Creates an instance of AuthGuard.
     * 私有构造，拒绝通过 new 创建对象
     *
     * @memberof AuthGuard
     */
    private constructor() { }

    /**
     * 获取应用数据
     *
     * @param {string} url url 请求路径
     * @param {*} [params={}] 请求参数
     * @param {*} [router] 路由对象
     * @returns {Promise<any>} 请求相响应对象
     * @memberof AuthGuard
     */
    authGuard(url: string, params: any = {}, router: any): any {
        return new Promise((resolve: any, reject: any) => {
            AppNoAuthDataService.getInstance().mountedAppBasicData().then((result: any) => {
                if (result) {
                    const routeParams: IParams = Util.getRouteParams(window.location.href);
                    if (routeParams && routeParams.redirect_uri) {
                        router.push({ name: 'login' });
                        resolve(false);
                    } else {
                        const Environment = AppServiceBase.getInstance().getAppEnvironment();
                        if (Environment && Environment.SaaSMode) {
                            if (getSessionStorage('activeOrgData')) {
                                this.getAppData(url, params, router).then((result: any) => {
                                    result ? resolve(true) : reject(false);
                                });
                            } else {
                                this.getOrgsByDcsystem(router).then((result: boolean) => {
                                    if (!result) {
                                        this.initAppService(router).then(() => reject(false));
                                    } else {
                                        this.getAppData(url, params, router).then((result: any) => {
                                            result ? resolve(true) : reject(false);
                                        });
                                    }
                                });
                            }
                        } else {
                            this.getAppData(url, params, router).then((result: any) => {
                                result ? resolve(true) : reject(false);
                            });
                        }
                    }
                }else{
                    resolve(false);
                }
            })
        });
    }

    /**
     * 通过租户获取组织数据
     *
     * @memberof AuthGuard
     */
    getOrgsByDcsystem(_router: any): Promise<boolean> {
        return new Promise((resolve: any) => {
            const tempViewParam = ViewTool.getDcSystemIdViewParam();
            if (tempViewParam.srfdcsystem) {
                AuthGuard.hooks.dcSystemBefore.callSync({ dcsystem: tempViewParam.srfdcsystem });
                setSessionStorage('dcsystem', tempViewParam);
                let requestUrl: string = `/uaa/getbydcsystem/${tempViewParam.srfdcsystem}`;
                const get: Promise<any> = Http.getInstance().get(requestUrl);
                get.then((response: any) => {
                    if (response && response.status === 200) {
                        let { data }: { data: any } = response;
                        AuthGuard.hooks.dcSystemAfter.callSync({ dcsystem: tempViewParam.srfdcsystem, data: data });
                        if (data && data.length > 0) {
                            setSessionStorage('orgsData', data);
                            setSessionStorage('activeOrgData', data[0]);
                        }
                        resolve(true);
                    } else {
                        resolve(false);
                    }
                }).catch(() => {
                    this.doNoLogin(_router, "登录失败，请联系管理员", true).then((result: any) => {
                        resolve(result);
                    })
                });
            } else {
                this.doNoLogin(_router, "登录失败，请联系管理员", true).then((result: any) => {
                    resolve(result);
                })
            }
        });
    }

    /**
     * 获取应用数据
     *
     * @param {string} url url 请求路径
     * @param {*} [params={}] 请求参数
     * @param {*} [router] 路由对象
     * @returns {Promise<boolean>} 是否通过
     * @memberof AuthGuard
     */
    getAppData(url: string, _params: any = {}, router: any): Promise<boolean> {
        return new Promise((resolve: any) => {
            const Environment = AppServiceBase.getInstance().getAppEnvironment();
            if (Environment.enableAppData) {
                AuthGuard.hooks.appBefore.callSync({ url: url, param: _params });
                const get: Promise<any> = Http.getInstance().get(url);
                get.then((response: any) => {
                    if (response && response.status === 200) {
                        let { data }: { data: any } = response;
                        AuthGuard.hooks.appAfter.callSync({ data: data });
                        if (data) {
                            // token认证把用户信息放入应用级数据
                            if (getCookie('ibzuaa-user')) {
                                let user: any = JSON.parse(getCookie('ibzuaa-user') as string);
                                let localAppData: any = {};
                                if (user.sessionParams) {
                                    localAppData = { context: user.sessionParams };
                                    Object.assign(localAppData, data);
                                }
                                data = JSON.parse(JSON.stringify(localAppData));
                            }
                            if (localStorage.getItem('localdata')) {
                                router.app.$store.commit(
                                    'addLocalData',
                                    JSON.parse(localStorage.getItem('localdata') as string),
                                );
                            }
                            router.app.$store.commit('addAppData', data);
                            // 提交统一资源数据
                            router.app.$store.dispatch('authresource/commitAuthData', data);
                        }
                    }
                    this.initAppService(router).then(() => resolve(true));
                }).catch(() => {
                    this.initAppService(router).then(() => {
                        this.doNoLogin(router, "登录失败，请联系管理员", true).then((result: any) => {
                            resolve(result);
                        })
                    });
                });
            } else {
                this.initAppService(router).then(() => resolve(true));
            }
        });
    }

    /**
     * 初始化应用服务
     *
     * @param {*} [router] 路由对象
     *
     * @memberof AuthGuard
     */
    async initAppService(router: any): Promise<void> {
        if (!AppServiceBase.getInstance().getAppStore()) {
            AppServiceBase.getInstance().setAppStore(router.app.$store);
        }
        AppServiceBase.getInstance().setI18n(i18n);
        AppServiceBase.getInstance().setRouter(router);
        AppServiceBase.getInstance().setAppMessageCenter(AppCenterService.getInstance(router.app.$store));
        AppServiceBase.getInstance().setNotification(AppNoticeService.getInstance());
        AppServiceBase.getInstance().setMicroAppService(MicroAppService.getInstance());
        AppServiceBase.getInstance().setViewLogicService(AppViewLogicService.getInstance());
        AppServiceBase.getInstance().setAppComponentService(AppComponentService);
        const service = new AppModelService();
        await GlobalHelp.install(service, async (strPath: string) => {
            let url: string = '';
            if (Environment.bDynamic) {
                url = `${Environment.remoteDynaPath}${strPath}`;
                const queryParam = {};
                const { dynamodeltag } = AppServiceBase.getInstance().getAppStore().getters.getAppData();
                if (dynamodeltag) {
                    Object.assign(queryParam, { dynamodeltag });
                }
                if (queryParam && Object.keys(queryParam).length > 0) {
                    url += `?${qs.stringify(queryParam)}`;
                }
            } else {
                const microAppService = AppServiceBase.getInstance().getMicroAppService();
                if (microAppService && microAppService.getIsMicroApp() && microAppService.getMicroAppFolder()) {
                    url = `./${microAppService.getMicroAppFolder()}/assets/model${strPath}`;
                } else {
                    url = `./assets/model${strPath}`;
                }
            }
            try {
                const result: any = await Http.getInstance().get(url);
                return result.data ? result.data : null;
            } catch (error) {
                return null;
            }
        }, { lang: Environment?.isEnableMultiLan ? handleLocaleMap(i18n.locale) : '' });
        this.initAppDynaEnvironment(service)
        AppServiceBase.getInstance().setAppModelDataObject(service.app);
        AppCenterService.getInstance(router.app.$store);
    }

    /**
     * 初始化动态环境参数
     *
     * @param {*} service
     * @memberof AuthGuard
     */
    initAppDynaEnvironment(service: any) {
        const appResources: any = service.getPSApplication()?.getAllPSAppResources();
        const dynaEnvironment = {};
        try {
            appResources?.forEach((item: IPSAppResource) => {
                if ((item.content?.indexOf("{") !== -1) && (item.content?.indexOf("}") !== -1)) {
                    Object.assign(dynaEnvironment, eval('(' + item.content + ')'));
                }
            });
        } catch (error) {
            LogUtil.error("应用资源配置错误");
        }
        AppServiceBase.getInstance().setAppDynaEnvironment(dynaEnvironment);
    }



    /**
     * 处理未登录异常情况
     *
     * @param {*} router 路由对象
     * @param {string} message 错误信息
     * @param {boolean} [isThrow=false] 是否必须抛出错误
     * @return {*} 
     * @memberof AuthGuard
     */
    public async doNoLogin(router: any, message: string, isThrow: boolean = false) {
        const gotoLogin: Function = () => {
            this.clearAppData(router.app.$store);
            if (MicroAppService.getInstance().getIsMicroApp()) {
                MicroAppService.getInstance().noticeBaseApp({ action: 'LOGOUT' })
            } else {
                if ((Environment as any).casLoginUrl) {
                    let pathname = location.pathname;
                    pathname = pathname.substring(0, pathname.lastIndexOf('/'));
                    window.location.href = `${(Environment as any).casLoginUrl}/login?service=${encodeURIComponent(
                        `${location.origin}${pathname}/cas-login.html?RU=${encodeURIComponent(location.href)}`,
                    )}`;
                } else if (Environment.loginUrl) {
                    window.location.href = `${Environment.loginUrl}?redirect=${window.location.href}`;
                } else {
                    if (Object.is(router.currentRoute.name, 'login')) {
                        NoticeHandler.errorHandler(message);
                        return;
                    }
                    router.push({ name: 'login', query: { redirect: window.location.hash.replace("#", '') } });
                }
            }
            return false;
        }
        if (isThrow) {
            gotoLogin();
        } else {
            return this.handleAccUserMode(router, gotoLogin);
        }
    }

    /**
     * 处理用户范围模式（0：未指定、 2：登录用户、 3：匿名用户及登录用户、 4：登录用户且拥有指定资源能力 ）
     *
     * @memberof AuthGuard
     */
    public async handleAccUserMode(router: any, gotoLogin: Function) {
        try {
            const activedPath: string = window.location.hash.substr(1);
            let activedRoute: any = router.getRoutes().find((item: any) => {
                return item.regex.test(activedPath);
            })
            if (activedRoute) {
                // 跳转应用首页视图
                if (activedRoute.redirect) {
                    activedRoute = router.getRoutes().find((item: any) => {
                        return item.meta.viewType === 'APPINDEX';
                    })
                    if (activedRoute && activedRoute.meta) {
                        if (activedRoute.meta.requireAuth) {
                            gotoLogin();
                        } else {
                            return true;
                        }
                    }
                } else {
                    // 自定义视图路径跳转
                    const dynaModelFilePath: string = await this.computeActivedViewFilePath(activedPath, activedRoute)
                    if (dynaModelFilePath) {
                        const modeldata = await ((await GetModelService()).getPSAppView(dynaModelFilePath)) as IPSAppView;
                        if ((modeldata.accUserMode === 0) || (modeldata.accUserMode === 3)) {
                            return true;
                        } else {
                            gotoLogin();
                        }
                    } else {
                        gotoLogin();
                    }
                }
            } else {
                gotoLogin();
            }
        } catch (error) {
            gotoLogin();
        }
    }

    /**
     * 计算视图动态路径
     *
     * @memberof AuthGuard
     */
    public async computeActivedViewFilePath(activedPath: string, route: any) {
        if (route && route.meta && route.meta.parameters) {
            let resource: string = route.meta.resource ? route.meta.resource.toLowerCase() : '';
            let activedView: any = route.meta.parameters.find((item: any) => {
                return item.pathName === 'views';
            });
            let localActivedView: any = Util.deepCopy(activedView);
            if (Object.is(localActivedView.parameterName, 'view') && Object.is(localActivedView.pathName, 'views')) {
                localActivedView.parameterName = this.parseUrlDynamicParam(activedPath, route).view;
            }
            if (localActivedView && localActivedView.parameterName) {
                const path = (await GetModelService()).getPSAppViewPath(`${resource}${localActivedView.parameterName}`);
                return path;
            } else {
                return '';
            }
        } else {
            return '';
        }
    }

    /**
     * 解析路由动态参数
     *
     * @memberof AuthGuard
     */
    public parseUrlDynamicParam(activedPath: string, route: any): any {
        const keys: Array<any> = route.regex.keys;
        const matchArray = route.regex.exec(activedPath);
        let tempValue: Object = {};
        keys.forEach((item: any, index: number) => {
            if (matchArray[index + 1]) {
                Object.defineProperty(tempValue, item.name, {
                    enumerable: true,
                    value: decodeURIComponent(matchArray[index + 1])
                });
            }
        });
        return tempValue;
    }

    /**
     * 清除应用数据
     *
     * @private
     * @memberof AuthGuard
     */
    private clearAppData(store: any) {
        // 清除user、token
        clearCookie('ibzuaa-token', true);
        clearCookie('ibzuaa-expired', true);
        clearCookie('ibzuaa-user', true);
        // 清除应用级数据
        localStorage.removeItem('localdata')
        store.commit('addAppData', {});
        store.dispatch('authresource/commitAuthData', {});
    }


}