import { immutable, circular, action, excludedInJSON } from '../decorators';
import { config, history, LEVEL_ENUM, Vertex, vertexsMap, Process, Logic, utils, ProcessComponentReturn, ProcessComponentVariable, ProcessComponentAttribute, ProcessComponentProperty, ProcessInterface, typeCheck, ActionOptions } from '..';
import processService from '../../service/process';

/**
 * 流程组件类
 */
export class ProcessComponent extends Vertex {
    /**
     * 概念类型
     */
    @immutable()
    public readonly level: LEVEL_ENUM = LEVEL_ENUM.processComponent;
    /**
     * 流程组件 Id
     */
    @immutable()
    public readonly id: string = undefined;
    /**
     * 流程组件名称
     */
    @immutable()
    public readonly name: string = undefined;
    /**
     * 流程组件标题
     */
    @immutable()
    public readonly title: string = undefined;
    /**
     * 流程组件描述
     */
    @immutable()
    public readonly description: string = undefined;
    /**
     * 流程组件类型
     */
    @immutable()
    public readonly type: string = undefined;
    /**
     * 流程组件输出参数
     */
    @immutable()
    public readonly returns: Array<any> = [];
    /**
     * 流程组件局部变量
     */
    @immutable()
    public readonly variables: Array<any> = [];
    /**
     * 流程组件逻辑 ID
     */
    @immutable()
    public readonly logicId: string = undefined;
    /**
     * 流程组件逻辑
     */
    @immutable()
    public readonly logic: Logic = undefined;
    /**
     * 流程组件属性
     */
    @immutable()
    public readonly destination: ProcessComponentAttribute = undefined;
    /**
     * 完成任务接口
     */
    @immutable()
    public readonly completeTaskInterface: ProcessInterface = undefined;
    /**
     * 所属流程 Id
     */
    @immutable()
    public readonly parentId: string = undefined;
    /**
     * 树组件的隐藏属性
     */
    @excludedInJSON()
    public readonly hidden: boolean = false;
    /**
     * 类型检查详情
     */
    @excludedInJSON()
    public readonly typeCheckResult: any = {};
    /**
     * 类型检查状态
     */
    @excludedInJSON()
    public readonly typeCheckStatus: string = 'success';
    /**
     * 所属流程
     */
    @circular()
    @immutable()
    public readonly process: Process = undefined;
    /**
     * 树组件的子节点字段
     */
    @excludedInJSON()
    @immutable()
    public readonly moreChildrenFields: Array<string> = ['returns', 'variables', 'properties', 'interfaces'];
    /**
     * 已存在名称集合
     */
    @excludedInJSON()
    @immutable()
    public readonly existingNames: Array<string> = [];
    /**
     * 接口列表，单纯用于 tree 展示
     */
    @excludedInJSON()
    @immutable()
    public readonly interfaces: Array<ProcessInterface> = [];
    /**
     * @param source 需要合并的部分参数
     */
    constructor(source?: Partial<ProcessComponent>) {
        super();
        this.assign(source);
    }
    /**
     * 添加流程组件
     */
    @action('添加流程组件')
    create() {
        this.process.childShapes.push(this);
        return this;
    }
    /**
     * 删除流程组件
     */
    @action('删除流程组件')
    delete() {
        const index = this.process.childShapes.indexOf(this);
        ~index && this.process.childShapes.splice(index, 1);
        this.destroy();
    }
    /**
     * 修改流程组件属性
     */
    async updateAttr(updateInterface?: boolean, actionOptions?: ActionOptions) {
        config.defaultApp?.emit('saving');

        const body = this.toPlainJSON();
        utils.logger.debug('修改流程组件', body);
        const { completeTaskInterface } = await processService.updateComponent({
            headers: {
                appId: config.defaultApp?.id,
                operationAction: actionOptions?.actionName || 'ProcessComponent.updateAttr',
                operationDesc: actionOptions?.actionDesc || `修改流程组件属性"${this.name}${this.title ? `(${this.title})` : ''}"`,
            },
            body,
        });
        // 流程接口会自动根据流程组件名称变化，更新流程接口的名称
        if (updateInterface && completeTaskInterface) {
            const { name, path, method } = completeTaskInterface;
            this.completeTaskInterface.assign({ name, path, method });
            this.completeTaskInterface.logic.assign({ name });
            this.process.service.emit('interfacesChange');
        }

        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.updateAttr(true, {
            actionDesc: `设置流程组件"${oldName}"的名称为"${name}"`,
        });
        // 流程逻辑会自动根据流程组件名称变化，更新逻辑的名称
        if (this.logic) {
            this.logic.assign({ name });
        }
    }
    /**
     * 设置流程组件标题
     * @param title 标题
     */
    @action('设置流程组件标题')
    async setTitle(title: string) {
        this.assign({ title });
        await this.updateAttr(false, {
            actionDesc: `设置流程组件"${this.name}"的标题为"${title}"`,
        });
    }
    /**
     * 设置流程组件描述
     * @param description 描述
     */
    @action('设置流程组件描述')
    async setDescription(description: string) {
        this.assign({ description });
        await this.updateAttr(false, {
            actionDesc: `设置流程组件"${this.name}"的描述为"${description}"`,
        });
    }
    /**
     * 设置流程组件值 (SequenceFlow)
     * @param flowValue 值
     */
    @action('设置流程组件值')
    async setFlowValue(flowValue: string) {
        this.assign({ flowValue });
        await this.updateAttr(false, {
            actionDesc: `设置流程组件值`,
        });
    }
    /**
     * 设置流程组件任务完成人 (UserTask)
     * @param assignee 任务完成人
     */
    @action('设置流程组件任务完成人')
    async setAssignee(assignee: Array<string>) {
        this.assign({ assignee });
        await this.updateAttr(false, {
            actionDesc: `设置流程组件任务完成人`,
        });
    }
    /**
     * 从后端 JSON 生成规范的 Param 对象
     */
    public static from(source: any, process: Process) {
        const processComponent = new ProcessComponent(source);
        processComponent.assign({
            process,
        });
        if (source) {
            const { returns = [], variables = [], properties = [], logicId, destination, completeTaskInterface, type } = source;
            processComponent.assign({
                hidden: ['StartNoneEvent', 'EndNoneEvent', 'SequenceFlow'].includes(type),
                returns: returns.map((rn: any) => (ProcessComponentReturn.from(rn, processComponent))),
                variables: variables.map((variable: any) => (ProcessComponentVariable.from(variable, processComponent))),
                properties: properties.map((property: any) => (ProcessComponentProperty.from(property, processComponent))),
            });
            // 包含 logicId 时，自动初始化 logic
            if (logicId) {
                // 可能情况下，复用已有 Logic 缓存，防止重复打开多个同样的 logic 编辑器
                processComponent.assign({
                    logic: vertexsMap.get(logicId) || Logic.from({ id: logicId }, processComponent),
                });
            }
            if (destination) {
                processComponent.assign({
                    destination: ProcessComponentAttribute.from(destination, processComponent),
                });
            }
            if (completeTaskInterface) {
                const ifce = ProcessInterface.from(completeTaskInterface, processComponent);
                processComponent.assign({
                    completeTaskInterface: ifce,
                    interfaces: [ifce],
                });
            }
        }
        return processComponent;
    }
    static assignTypeCheckResult(processComponent: ProcessComponent, typeCheckResult: any) {
        if (!processComponent || !typeCheckResult)
            return;

        typeCheck.push(typeCheckResult);
        const typeCheckStatus = typeCheckResult.typeCheckNote?.status || 'success';
        processComponent.assign({
            typeCheckResult,
            typeCheckStatus,
        });
    }
}

export default ProcessComponent;
