import { immutable, circular, action, excludedInJSON } from '../decorators';
import { config, history, LEVEL_ENUM, Vertex, Entity, Enum, PackageJSON, App, WebService, View, utils, Interface, updateDataTypeList, Structure, ActionOptions } from '..';
import pageService from '../../service/page';
import { traverse } from '../utils';
import { postServiceType } from '../../service/common/preprocess';

/**
 * 页面（入口页）类，后端路由控制
 * @category page
 */
export class Page extends Vertex {
    /**
     * 概念类型
     */
    @immutable()
    public readonly level: LEVEL_ENUM = LEVEL_ENUM.page;
    /**
     * 页面 Id
     */
    @immutable()
    public readonly id: string = undefined;
    /**
     * 页面名称
     */
    @immutable()
    public readonly name: string = undefined;
    /**
     * 页面标题
     */
    @immutable()
    public readonly title: string = undefined;
    /**
     * 是否接入权限
     */
    @immutable()
    public readonly auth: boolean = undefined;
    /**
     * 是否为首页
     */
    @immutable()
    public readonly isIndex: boolean = undefined;
    /**
     * 根页面视图
     */
    @immutable()
    public readonly rootView: View = undefined;
    /**
     * 所属前端服务 Id
     */
    @immutable()
    public readonly serviceId: string = undefined;
    /**
     * 所属前端服务
     */
    @circular()
    @immutable()
    public readonly service: WebService = undefined;
    /**
     * 树组件的子节点字段
     */
    @excludedInJSON()
    @immutable()
    public readonly childrenField: string = 'rootView.children';
    /**
     * 树组件的子节点字段
     */
    @excludedInJSON()
    @immutable()
    public readonly moreChildrenFields: Array<string> = ['rootView.$def.params', 'rootView.$def.variables', 'rootView.$def.logics'];
    /**
     * @param source 需要合并的部分参数
     */
    constructor(source?: Partial<Page>) {
        super();
        source && this.assign(source);
    }
    /**
     * 加载页面详情
     * @requires this.id
     */
    async load() {
        const result = await pageService.loadPage({
            path: {
                id: this.id,
            },
        });
        this.assign(result);

        traverse((current) => {
            if (current.parent) {
                const view = current.parent.children[current.index] = new View(current.node);
                view.assign({ page: this, parent: current.parent });
                // view.parseAll();
            }
        }, { node: this.rootView });
        const rootView = new View(this.rootView);
        rootView.assign({ page: this });
        
        this.assign({ rootView });
    }

    addData(res: any) {
        const microService = this.service.app.firstMicroService;
        const interfaces = res.interfaces as Array<Interface>;
        if (interfaces && interfaces.length) {
            interfaces.forEach((item, index) => {
                const itface = interfaces[index] = Interface.from(item, microService);
                postServiceType(itface);
            });
            microService.interfaces.unshift(...interfaces);
            microService.globalLogic.globalLogics.unshift(...interfaces);
            microService.emit('interfacesChange');
        }

        const enums = res.enums as Array<Enum>;
        if (enums && enums.length) {
            enums.forEach((item, index) => enums[index] = Enum.from(item, microService));
            microService.data.enums.unshift(...enums);
            updateDataTypeList();
        }

        const entities = res.entities as Array<Entity>;
        if (entities && entities.length) {
            entities.forEach((item, index) => entities[index] = Entity.from(item, microService));
            microService.data.entities.unshift(...entities);
            updateDataTypeList();
        }

        const structures = res.structures as Array<Structure>;
        if (structures && structures.length) {
            structures.forEach((item, index) => structures[index] = Structure.from(item, microService));
            microService.data.structures.unshift(...structures);
            updateDataTypeList();
        }
    }

    /**
     * 添加页面
     */
    @action('导入页面')
    async importPage(none?: void, actionOptions?: ActionOptions, then?: () => Promise<any>) {
        config.defaultApp?.emit('saving');
        const body = this.toJSON();
        utils.logger.debug('添加页面', body);
        const result = await pageService.importPage({
            headers: {
                appId: config.defaultApp?.id,
                operationAction: actionOptions?.actionName || 'Page.create',
                operationDesc: actionOptions?.actionDesc || `添加页面"${this.name}${this.title ? `(${this.title})` : ''}"`,
            },
            body,
        });
      
        this.deepPick(result.page, ['id']);
        // 添加数据和接口
        this.addData(result);
        const rootView = View.from(result.page.rootView, null, this);
        rootView.assign({
            tempPath: `/${rootView.name}`,
            code: `/ID_${rootView.id}`,
        });
        // page 添加一次 rootView
        this.assign({ rootView });
        // Destination选择页面时用的是page的code，这里需要赋值下
        this.assign({
            tempPath: `/${rootView.name}`,
            code: `/ID_${rootView.id}`,
        });
       this.rootView.attachNodePath();
        if(result.page.isIndex) {
            const tasks = this.service.pages.filter((page) => page.isIndex && page.id !== result.page.id)
                .map((page) => {
                    page.assign({ isIndex: false });
                    return page.update();
                });
            Promise.all(tasks);
        }
    
        await then?.();
        this.service.emit('pageTreeChange');

        const microService = this.service.app.firstMicroService;
        microService.emit('dataTypesChange');
        microService.emit('enumsChange');
        microService.emit('vertexIdToNameChange');
        
        this.rootView.emit('change');
        // this.assign(Page.from(this, this.service));
        
        await config.defaultApp?.history.load();
        config.defaultApp?.emit('saved');
        return this;
    }

    /**
     * 添加页面
     */
    @action('添加页面')
    async create(none?: void, actionOptions?: ActionOptions, then?: () => Promise<any>) {
        config.defaultApp?.emit('saving');

        const body = this.toJSON();
        utils.logger.debug('添加页面', body);
        const result = await pageService.addPage({
            headers: {
                appId: config.defaultApp?.id,
                operationAction: actionOptions?.actionName || 'Page.create',
                operationDesc: actionOptions?.actionDesc || `添加页面"${this.name}${this.title ? `(${this.title})` : ''}"`,
            },
            body,
        });
        this.deepPick(result, ['id']);
        this.rootView.attachNodePath();
        if(result.isIndex) {
            const tasks = this.service.pages.filter((page) => page.isIndex && page.id !== result.id)
                .map((page) => {
                    page.assign({ isIndex: false });
                    return page.update();
                });
            Promise.all(tasks);
        }
        
        await then?.();
        this.service.emit('pageTreeChange');
        this.rootView.emit('change');
        // this.assign(Page.from(this, this.service));
        
        await config.defaultApp?.history.load();
        config.defaultApp?.emit('saved');
        return this;
    }
    /**
     * 删除页面
     */
    @action('删除页面')
    async delete(none?: void, actionOptions?: ActionOptions) {
        config.defaultApp?.emit('saving');

        try {
            await pageService.removePage({
                headers: {
                    appId: config.defaultApp?.id,
                    operationAction: actionOptions?.actionName || 'Page.delete',
                    operationDesc: actionOptions?.actionDesc || `删除页面"${this.name}${this.title ? `(${this.title})` : ''}"`,
                },
                path: {
                    id: this.id,
                },
            });
        } catch(err) {
            await config.defaultApp?.history.load();
            throw err;
        }

        const index = this.service.pages.indexOf(this);
        ~index && this.service.pages.splice(index, 1);
        this.destroy();
        this.service.emit('pageTreeChange');

        await config.defaultApp?.history.load();
        config.defaultApp?.emit('saved');
    }
    /**
     * 修改页面
     */
    async update(none?: void, actionOptions?: ActionOptions, then?: () => Promise<any>) {
        config.defaultApp?.emit('saving');

        const body = this.toPlainJSON();
        utils.logger.debug('修改页面', body);
        const result = await pageService.update({
            headers: {
                appId: config.defaultApp?.id,
                operationAction: actionOptions?.actionName || 'Page.delete',
                operationDesc: actionOptions?.actionDesc || `修改页面"${this.name}${this.title ? `(${this.title})` : ''}"`,
            },
            body,
        });

        await config.defaultApp?.history.load();
        config.defaultApp?.emit('saved');
        return this;
    }
    /**
     * 设为首页
     */
    @action('设为首页')
    async setAsIndex() {
        config.defaultApp?.emit('saving');

        const tasks = this.service.pages.filter((page) => page.isIndex)
            .map((page) => {
                page.assign({ isIndex: false });
                return page.update();
            });
        this.assign({ isIndex: true });
        tasks.push(this.update(undefined, {
            actionDesc: `设置页面"${this.name}"为首页`,
        }));
        await Promise.all(tasks);

        this.service.emit('pageTreeChange');

        await config.defaultApp?.history.load();
        config.defaultApp?.emit('saved');
    }
    /**
     * 设置是否开启权限控制
     */
    @action('设置是否开启权限控制')
    async setAuth(auth: boolean) {
        this.assign({ auth });
        await this.update(undefined, {
            actionDesc: `设置${this.auth ? '开启' : '关闭'}页面"${this.name}"权限控制`,
        });
    }
    // /**
    //  * 加载子页面详情
    //  * @requires this.id
    //  * @deprecated
    //  */
    // async loadViewTree() {
    //     let rootView = await pageService.loadViewTree({
    //         query: {
    //             id: this.id,
    //         },
    //         config: {
    //             mock: config.mock,
    //         },
    //     });

    //     traverse((current) => {
    //         if (current.parent) {
    //             const view = current.parent.children[current.index] = new View(current.node);
    //             view.assign({ page: this, parent: current.parent });
    //             view.parseAll();
    //         }
    //     }, { node: rootView, parent: null, index: null, nodePath: '' });
    //     rootView = new View(rootView);
    //     rootView.parseAll();

    //     this.assign({ rootView });

    //     return rootView;
    // }
    /**
     * 从后端 JSON 生成规范的 Param 对象
     */
    public static from(source: any, service: WebService) {
        const page = new Page(source);

        page.assign({
            rootView: View.from(page.rootView, null, page),
            service,
            tempPath: page.rootView? `/${page.rootView.name}`: '',
            code: page.rootView?`/ID_${page.rootView.id}`: '',
        });

        return page;
    }
}

export default Page;
