import { HttpErrorResponse } from '@angular/common/http';
import { Injector } from '@angular/core';
import { NcApplication, NcMenu, NcRoute, NgCortexService } from '@ng-cortex/core';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { map, tap } from 'rxjs/operators';
import { environment } from '../../../../../environments/environment';
import { routes } from '../../../dev-routing.module';

/** 程序启动制造器 */
export function AppStartupFactory(injector: Injector): () => Promise<void> {
    const nzNotificationService = injector.get(NzNotificationService);
    const ngCortexService = injector.get(NgCortexService);
    return () => ngCortexService
        .initialize({
            resconfigUrl: environment.resconfigUrl,
            coreService: environment.coreService,
            titleSuffix: environment.titleSuffix,
            storageKeyForToken: environment.storageKeyForToken,
            routeForLogin: '/login',
            routeForApplicationIndex: '/dev',
            routeForApplication403: '/dev/403',
            routeForApplication404: '/dev/404',
            routeForApplication500: '/dev/500',
            routeReuse: environment.routeReuse,
            dev: true
        })
        .pipe(map(() => {
            (window as any).Spinner.done();
            injectDevApplication(ngCortexService);
            injectDevMenuList(ngCortexService);
            updateRouteConfigMap(ngCortexService);
        }))
        .pipe(tap(() => { }, (httpErrorResponse: HttpErrorResponse) => {
            (window as any).Spinner.done();
            nzNotificationService.error('初始化失败', httpErrorResponse.error && httpErrorResponse.error.message || httpErrorResponse.statusText);
            const errorContainer = document.createElement('div');
            errorContainer.innerHTML = '<div style="position: absolute; top: 0px; left: 0px; min-width: 100%; min-height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center;">' +
                '<img src="/assets/images/init-fail.svg" style="height: 300px; margin-bottom: 24px;">' +
                '<span class="ant-result-title">初始化失败</span>' +
                '</div>';
            document.body.appendChild(errorContainer.firstElementChild!);
        }))
        .toPromise();
}

/**
 * 注入开发应用
 * @param ngCortexService ngCortex服务
 */
function injectDevApplication(ngCortexService: NgCortexService): void {
    const devApplication: NcApplication = {
        name: '调试应用',
        code: 'dev',
        description: '一个开发调试的虚拟应用',
        icon: 'bug',
        groupName: '调试',
        common: false,
        sequence: 1
    };
    ngCortexService.data.applicationList = [devApplication];
    ngCortexService.data.currentApplication = devApplication;
    (ngCortexService as any)._applicationList.next(ngCortexService.data.applicationList);
    (ngCortexService as any)._currentApplication.next(ngCortexService.data.currentApplication);
}

/**
 * 注入开发菜单列表
 * @param ngCortexService ngCortex服务
 */
function injectDevMenuList(ngCortexService: NgCortexService): void {
    const menuList: NcMenu[] = [];
    routes.forEach(routeConfig => {
        const routeConfigData = routeConfig.data!;
        if (routeConfigData.major && !routeConfigData.hidden) {
            menuList.push({
                name: routeConfigData.name!,
                icon: 'file',
                type: '菜单',
                level: 1,
                url: '/dev/<%= getSeparatorCase(microFrontendName) %>/' + routeConfig.path
            });
        }
    });
    ngCortexService.data.menuList = menuList;
    (ngCortexService as any)._menuList.next(ngCortexService.data.menuList);
}

/**
 * 更新路由配置映射
 * @param ngCortexService ngCortex服务
 */
function updateRouteConfigMap(ngCortexService: NgCortexService): void {
    const routeConfigMap: Map<string, NcRoute[]> = new Map();
    const eachRouteFn = (routeConfig: NcRoute[], pathList?: string[]): void => {
        pathList = pathList || [];
        for (const i in routeConfig) {
            const currentRouteConfig = routeConfig[i];
            const currentPathList = currentRouteConfig.path ? pathList.concat(currentRouteConfig.path.split('/')).filter(path => path) : pathList;
            const currentRoute = '^\\\/' + currentPathList.map(path => path.replace(/^\:.+$/, '[^\\\/]+').replace(/^\*{2}$/, '.*')).join('\\\/') + '$';
            const routeConfigList = routeConfigMap.get(currentRoute) || [];
            routeConfigList.push(currentRouteConfig);
            routeConfigMap.set(currentRoute, routeConfigList);
            if (currentRouteConfig.children !== undefined) {
                eachRouteFn(currentRouteConfig.children, currentPathList);
            }
        }
    };
    (ngCortexService as any)._routeConfigMap.forEach((routeConfigList: NcRoute[], regexp: string) => {
        routeConfigMap.set(regexp, routeConfigList);
        if (regexp.includes('<%= getSeparatorCase(microFrontendName) %>') && new RegExp(regexp).test(ngCortexService.routeForApplicationIndex + '/<%= getSeparatorCase(microFrontendName) %>')) {
            eachRouteFn(routes, regexp.replace(/\^|\$/g, '').split('\\\/').filter(segment => segment));
        }
    });
    (ngCortexService as any)._routeConfigMap = routeConfigMap;
}
