import { IContext } from '@ibizstudio/api';
import { notNilEmpty } from 'qx-util';
import { Vue, Component, Emit, Prop } from 'vue-property-decorator';
import { OpenParams } from './interface/open-params';
import './studio-model-editor.less';

/**
 * 模型编辑器
 *
 * @export
 * @class StudioModelEditor
 * @extends {Vue}
 */
@Component({})
export class StudioModelEditor extends Vue {
    /**
     * 是否已经关闭
     *
     * @type {boolean}
     * @memberof StudioModelEditor
     */
    @Prop({ default: false })
    isClose!: boolean;

    /**
     * 数据是否变更
     *
     * @protected
     * @type {boolean}
     * @memberof StudioModelEditor
     */
    protected isDataChange: boolean = false;

    /**
     * 是否正在加载中
     *
     * @protected
     * @type {boolean}
     * @memberof StudioModelEditor
     */
    protected isLoading: boolean = false;

    /**
     * 加载中文本
     *
     * @protected
     * @type {string}
     * @memberof StudioModelEditor
     */
    protected loadingText: string = '加载中...';

    /**
     * 请求参数
     *
     * @protected
     * @type {OpenParams}
     * @memberof StudioModelEditor
     */
    protected param?: OpenParams;

    /**
     * 上下文
     *
     * @author chitanda
     * @date 2021-03-31 17:03:52
     * @protected
     * @type {IContext}
     */
    protected context: IContext = {};

    /**
     * 模型字符串，用于编辑
     *
     * @protected
     * @type {string}
     * @memberof StudioModelEditor
     */
    protected modelStr: string = '';

    /**
     * 关闭界面
     *
     * @protected
     * @returns {*}
     * @memberof StudioModelEditor
     */
    @Emit('close')
    protected close(): any {}

    /**
     * 表单保存
     *
     * @protected
     * @returns {*}
     * @memberof StudioModelEditor
     */
    @Emit('saved')
    protected saved(): any {}

    /**
     * 关闭模型编辑
     *
     * @protected
     * @memberof StudioModelEditor
     */
    protected closeView(): void {
        if (this.isClose) {
            return;
        }
        if (!this.isDataChange) {
            this.close();
        } else {
            this.$Modal.confirm({
                title: '确认退出?',
                content: '修改模型尚未保存，确认退出吗?',
                onOk: () => this.close(),
            });
        }
    }

    /**
     * 组件创建完毕
     *
     * @memberof StudioModelEditor
     */
    created(): void {
        document.addEventListener('keydown', (e: KeyboardEvent) => {
            if (e.keyCode === 27) {
                this.closeView();
            }
        });
    }

    /**
     * 设置参数
     *
     * @author chitanda
     * @date 2021-03-31 17:03:10
     * @param {IContext} context
     * @param {OpenParams} params
     * @return {*}  {void}
     */
    setParam(context: IContext, params: OpenParams): void {
        if (this.isClose) {
            return;
        }
        if (params && !Object.is(JSON.stringify(this.param), JSON.stringify(params))) {
            this.context = context;
            this.param = params;
            this.modelStr = '';
            this.loadModel();
        }
    }

    /**
     * 重新加载
     *
     * @protected
     * @memberof StudioModelEditor
     */
    protected reload(): void {
        if (this.isDataChange) {
            this.$Modal.confirm({
                title: '确认刷新?',
                content: '修改模型尚未保存，确认刷新吗?',
                onOk: () => this.loadModel(),
            });
        } else {
            this.loadModel();
        }
    }

    /**
     * 保存
     *
     * @protected
     * @param {boolean} [isCloseView]
     * @memberof StudioModelEditor
     */
    protected save(isCloseView?: boolean): void {
        this.saveModel(null, isCloseView);
    }

    /**
     * 加载模型数据
     *
     * @protected
     * @returns {Promise<void>}
     * @memberof StudioModelEditor
     */
    protected async loadModel(): Promise<void> {
        this.showLoading('模型加载中...');
        try {
            const entityName = this.param?.entityName;
            if (notNilEmpty(entityName)) {
                const s = await ___ibz___.gs.getService(entityName!) as any;
                const model = await s.getLocalModel(this.context, {});
                this.modelStr = JSON.stringify(model, null, 2);
            } else {
                this.$Message.error('未指定实体，无法加载模型!');
            }
        } catch (err: any) {
            this.$Message.error(err.message);
        }
        this.hiddenLoading();
    }

    /**
     * 保存模型
     *
     * @protected
     * @param {*} params 保存传递参数
     * @param {boolean} [isCloseView] 保存完成是否关闭当前视图
     * @returns {Promise<void>}
     * @memberof StudioModelEditor
     */
    protected async saveModel(params: any, isCloseView?: boolean): Promise<void> {
        if (!this.modelFormat()) {
            return;
        }
        this.showLoading('模型保存中...');
        try {
            const entityName = this.param?.entityName;
            if (notNilEmpty(entityName)) {
                const s = await ___ibz___.gs.getService(entityName!) as any;
                await s.setLocalModel(this.context, JSON.parse(this.modelStr));
                this.$emit('saved');
                if (isCloseView) {
                    this.close();
                }
            } else {
                this.$Message.error('未指定实体，无法加载模型!');
            }
        } catch (err: any) {
            this.$Message.error(err.message);
        }
        this.hiddenLoading();
    }

    /**
     * 模型变更
     *
     * @protected
     * @param {string} val
     * @memberof StudioModelEditor
     */
    protected modelChange(val: string): void {
        if (!Object.is(this.modelStr, val)) {
            this.modelStr = val;
            this.isDataChange = true;
        }
    }

    /**
     * 格式化模型
     *
     * @protected
     * @memberof StudioModelEditor
     */
    protected modelFormat(): boolean {
        try {
            this.modelStr = JSON.stringify(JSON.parse(this.modelStr), null, 2);
            return true;
        } catch (error) {
            this.$Message.error('格式有误，请检查!');
        }
        return false;
    }

    /**
     * 绘制内容
     *
     * @returns {*}
     * @memberof StudioModelEditor
     */
    render(): any {
        return (
            <div
                class='studio-model-editor'
                v-loading={this.isLoading}
                element-loading-text={this.loadingText}
                element-loading-spinner='el-icon-loading'
                element-loading-background='rgba(0, 0, 0, 0.8)'
            >
                <div class='studio-model-editor-header'>
                    <div class='title'>模型编辑</div>
                    <div class='actions'>
                        <i-button size='small' title='刷新数据' on-click={() => this.reload()}>
                            刷新
                        </i-button>
                        <i-button size='small' title='格式化JSON数据' on-click={() => this.modelFormat()}>
                            格式化
                        </i-button>
                        <i-button size='small' title='保存数据并关闭界面' on-click={() => this.save(true)}>
                            保存并关闭
                        </i-button>
                        <i-button
                            size='small'
                            class='close'
                            type='text'
                            ghost
                            icon='md-close'
                            on-click={() => this.closeView()}
                        />
                    </div>
                </div>
                <div class='studio-model-editor-content'>
                    <app-code-editor
                        key='code-content-ftl'
                        code={this.modelStr}
                        on-change={(val: string) => this.modelChange(val)}
                        codetype='json'
                        height='100%'
                    ></app-code-editor>
                </div>
            </div>
        );
    }

    /**
     * 显示加载动画
     *
     * @protected
     * @param {string} [loadingText]
     * @memberof StudioModelEditor
     */
    protected showLoading(loadingText?: string): void {
        if (loadingText) {
            this.loadingText = loadingText;
        }
        this.isLoading = true;
    }

    /**
     * 隐藏加载动画
     *
     * @protected
     * @memberof StudioModelEditor
     */
    protected hiddenLoading(): void {
        this.isLoading = false;
    }
}
