import { immutable, circular, excludedInJSON, action } from '../decorators';
import {
    config, utils, LEVEL_ENUM, Vertex, Schema,
    Structure, ActionOptions,
} from '..';
import { structureService } from '../../service/data';
import { getBasicTypeDefaultValue } from './basicTypes';
import { convert2RefType } from './dataTypeUtils';
import { updateAllVariablesChildrenSchema } from '../logic/BaseVariable';
import { schemaService } from '../../service/common';

/**
 * 数据结构属性类
 */
export class StructureProperty extends Vertex implements Schema {
    /**
     * 概念类型
     */
    @immutable()
    public level: LEVEL_ENUM = LEVEL_ENUM.property;
    /**
     * Id
     */
    @immutable()
    public readonly id: string = undefined;
    /**
     * 名称
     */
    @immutable()
    public readonly name: string = undefined;
    /**
     * 标签
     */
    @immutable()
    public readonly label: string = undefined;
    /**
     * 描述
     */
    @immutable()
    public readonly description: string = undefined;
    /**
     * type
     */
    @immutable()
    public readonly type: string = undefined;
    /**
     * 数据格式
     */
    @immutable()
    public readonly format: string = undefined;
    /**
     * generic 数据格式
     */
    @immutable()
    public readonly typeInstantiation: Schema = undefined;
    /**
     * 是否必须
     */
    @immutable()
    public readonly required: boolean = undefined;
    /**
     * 数据类型
     */
    @immutable()
    public readonly $ref: string = undefined;
    /**
     * 是否为数组，老的 Schema 中仍然用这种形式
     */
    @immutable()
    public readonly isArray: boolean = undefined;
    /**
     * 规则列表
     */
    @immutable()
    public readonly rules: any = undefined;
    /**
     * 默认值
     */
    @immutable()
    public readonly defaultValue: string | boolean | number = undefined;
    /**
     * 父级 Id
     */
    @immutable()
    public readonly structureId: string = undefined;
    /**
     * 父级引用
     */
    @circular()
    @immutable()
    public root: Structure = undefined;
    /**
     * 节点是否为叶子节点
     * 前端 UI 状态
     */
    @excludedInJSON()
    public isLeaf = true;
    /**
     * 周边存在的名称
     */
    @excludedInJSON()
    public existingNames: Array<string> = [];
    /**
     * @param source 需要合并的部分参数
     */
    constructor(source?: Partial<StructureProperty>) {
        super();
        source && this.assign(source);
    }
    /**
     * 添加数据结构属性
     */
    @action('添加数据结构属性')
    async create(none?: void, actionOptions?: ActionOptions) {
        config.defaultApp?.emit('saving');
        const body = this.toJSON();
        body._posIndex = this.root.propertyList.indexOf(this);
        utils.logger.debug('添加数据结构属性', body);
        const result: StructureProperty = await structureService.addProperty({
            headers: {
                appId: config.defaultApp?.id,
                operationAction: actionOptions?.actionName || 'StructureProperty.create',
                operationDesc: actionOptions?.actionDesc || `添加数据结构"${this.root.name}"属性"${this.name}"`,
            },
            body,
        });
        // convert2RefType(result);
        this.deepPick(result, ['id']);

        updateAllVariablesChildrenSchema();
        this.root.dataNode.service.emit('dataTypesChange');
        this.root.dataNode.service.emit('vertexIdToNameChange', this.id, this.name);

        await config.defaultApp?.history.load();
        config.defaultApp?.emit('saved');
        return this;
    }
    /**
     * 删除数据结构属性
     */
    @action('删除数据结构属性')
    async delete(none?: void, actionOptions?: ActionOptions) {
        config.defaultApp?.emit('saving');

        if (this.id) {
            await structureService.deleteProperty({
                headers: {
                    appId: config.defaultApp?.id,
                    operationAction: actionOptions?.actionName || 'StructureProperty.delete',
                    operationDesc: actionOptions?.actionDesc || `删除数据结构"${this.root.name}"属性"${this.name}"`,
                },
                query: {
                    id: this.id,
                },
            });
        }

        const index = this.root.propertyList.indexOf(this);
        ~index && this.root.propertyList.splice(index, 1);

        updateAllVariablesChildrenSchema();
        this.destroy();
        this.root.dataNode.service.emit('dataTypesChange');

        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.toJSON();
        delete body.schemaRef;
        utils.logger.debug('修改数据结构属性', body);
        const result = await structureService.updateProperty({
            headers: {
                appId: config.defaultApp?.id,
                operationAction: actionOptions?.actionName || 'StructureProperty.update',
                operationDesc: actionOptions?.actionDesc || `修改数据结构"${this.root.name}"属性"${this.name}"`,
            },
            body,
        });

        await then?.();
        await config.defaultApp?.history.load();
        config.defaultApp?.emit('saved');
        return this;
    }
    /**
     * 设置数据结构属性名称
     * @param name 名称
     */
    @action('设置数据结构属性名称')
    async setName(name: string) {
        const oldName = this.name;
        this.assign({ name });
        await this.update(undefined, {
            actionDesc: `设置数据结构"${this.root.name}"的属性"${oldName}"的名称为"${name}"`,
        });

        this.root.dataNode.service.emit('dataTypesChange');
        this.root.dataNode.service.emit('vertexIdToNameChange', this.id, this.name);
    }
    /**
     * 设置数据结构属性标题
     * @param label 标题
     */
    @action('设置数据结构属性标题')
    async setLabel(label: string) {
        this.assign({ label });
        await this.update(undefined, {
            actionDesc: `设置数据结构"${this.root.name}"的属性"${this.name}"的标题为"${label}"`,
        });
    }
    /**
     * 设置数据结构属性描述
     * @param description 描述
     */
    @action('设置数据结构属性描述')
    async setDescription(description: string) {
        this.assign({ description });
        await this.update(undefined, {
            actionDesc: `设置数据结构"${this.root.name}"的属性"${this.name}"的描述为"${description}"`,
        });
    }
    /**
     * 查找schema 顶点被引用的逻辑顶点列表
     */
    async getSchemaUsage() {
        const result = await schemaService.getSchemaUsage({
            query: {
                schemaId: this.id,
                valSource: 'structure',
            },
        });
        return result;
    }
    /**
     * 设置数据结构属性类型
     */
    @action('设置数据结构属性类型')
    async setDataType(schema: Schema) {
        // 用于update失败后还原数据
        const originalData = {
            $ref: this.$ref,
            type: this.type,
            format: this.format,
            typeInstantiation: this.typeInstantiation,
            defaultValue: this.defaultValue,
            rules: this.rules,
        };
        this.assign({
            $ref: undefined, //引用到Entity或者structure
            type: undefined,
            format: undefined,
            typeInstantiation: undefined,
        });
        this.assign(schema);
        this.assign({
            defaultValue: getBasicTypeDefaultValue(),
            rules: [],
        });
        try {
            await this.update(undefined, {
                actionDesc: `设置数据结构"${this.root.name}"的属性"${this.name}"的类型为"${schema.typeKey}"`,
            });

            updateAllVariablesChildrenSchema();
            this.root.dataNode.service.emit('dataTypesChange');
        } catch (err) {
            this.assign(convert2RefType(originalData));
            config.defaultApp?.emit('saved');
            throw err;
        }
    }
    /**
     * 设置数据结构属性是否为列表
     * @param isArray
     */
    @action('设置数据结构属性是否为列表')
    async setAsList(isArray: boolean) {
        this.assign({ isArray });
        this.assign({ defaultValue: getBasicTypeDefaultValue() });

        await this.update(undefined, {
            actionDesc: `设置数据结构"${this.root.name}"的属性"${this.name}"${isArray ? '为' : '不为'}列表`,
        });

        this.root.dataNode.service.emit('dataTypesChange');
    }
    /**
     * 设置数据结构属性默认值
     */
    @action('设置数据结构属性默认值')
    async setDefaultValue(defaultValue: string) {
        this.assign({ defaultValue });
        await this.update(undefined, {
            actionDesc: `设置数据结构"${this.root.name}"的属性"${this.name}"的默认值为"${defaultValue}"`,
        });

        this.root.dataNode.service.emit('dataTypesChange');
    }
    /**
     * 设置数据结构属性必须
     * @param required 必须
     */
    @action('设置数据结构属性必须')
    async setRequired(required: boolean) {
        this.assign({ required });
        await this.update(undefined, {
            actionDesc: `设置数据结构"${this.root.name}"的属性"${this.name}"为"${required ? '必须' : '不必须'}"`,
        });

        this.root.dataNode.service.emit('dataTypesChange');
    }
    @action('设置数据结构属性规则')
    async setRules(rules: any) {
        this.assign({ rules });
        await this.update(undefined, {
            actionDesc: `设置数据结构属性规则`,
        });
    }
    /**
     * 从后端 JSON 生成规范的 StructureProperty 对象
     */
    public static from(source: any, root: Structure) {
        convert2RefType(source.schema);
    }
}

export default StructureProperty;
