import { _decorator, CCString, error } from 'cc';
import { StringFormatFunction } from './StringFormat';
import { VMBase } from './VMBase';
import { VMEnv } from './VMEnv';

const { ccclass, property, menu, executeInEditMode, help } = _decorator;

const LABEL_TYPE = {
    CC_LABEL: 'cc.Label',
    CC_RICH_TEXT: 'cc.RichText',
    CC_EDIT_BOX: 'cc.EditBox'
}

/**
 *  [VM-Label]
 *  专门处理 Label 相关 的组件，如 ccLabel,ccRichText,ccEditBox
 *  可以使用模板化的方式将数据写入,可以处理字符串格式等
 *  todo 加入stringFormat 可以解析转换常见的字符串格式
 */
@ccclass
@executeInEditMode
@menu('OopsFramework/Mvvm/VM-Label （标签）')
@help('https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037641&doc_id=2873565')
export default class VMLabel extends VMBase {
    @property({
        tooltip: '是否启用模板代码,只能在运行时之前设置,\n将会动态解析模板语法 {{0}},并且自动设置监听的路径'
    })
    templateMode: boolean = false;

    @property({
        visible() {
            // @ts-ignore
            return this.templateMode === false;
        }
    })
    watchPath: string = '';

    @property({
        readonly: true
    })
    protected labelType: string = LABEL_TYPE.CC_LABEL;

    @property({
        type: [CCString],
        visible() {
            // @ts-ignore
            return this.templateMode === true;
        }
    })
    /** 按照匹配参数顺序保存的 path 数组 （固定） */
    protected watchPathArr: string[] = [];

    /** 按照路径参数顺序保存的 值的数组（固定）*/
    protected templateValueArr: any[] = [];

    /** 保存着字符模板格式的数组 (只会影响显示参数) */
    private templateFormatArr: string[] = [];

    /** 源字符串 */
    protected originText: string | null = null;

    onRestore() {
        this.checkLabel();
    }

    onLoad() {
        super.onLoad();
        this.checkLabel();

        if (VMEnv.editor) return;

        if (this.templateMode) {
            this.originText = this.getLabelValue();
            this.parseTemplate();
        }
    }

    start() {
        if (VMEnv.editor) return;

        this.onValueInit();
    }

    /** 解析模板 获取初始格式化字符串格式的信息 */
    parseTemplate() {
        let regexAll = /\{\{(.+?)\}\}/g;                // 匹配： 所有的{{value}}
        let regex = /\{\{(.+?)\}\}/;                    // 匹配： {{value}} 中的 value
        let res = this.originText!.match(regexAll);     // 匹配结果数组
        if (res == null) return;
        for (let i = 0; i < res.length; i++) {
            const e = res[i];
            let arr = e.match(regex);
            let matchName = arr![1];
            // let paramIndex = parseInt(matchName) || 0;
            let matchInfo = matchName.split(':')[1] || '';
            this.templateFormatArr[i] = matchInfo;
        }
    }

    /** 获取解析字符串模板后得到的值 */
    getReplaceText() {
        if (!this.originText) return "";
        let regexAll = /\{\{(.+?)\}\}/g;                    // 匹配： 所有的{{value}}
        let regex = /\{\{(.+?)\}\}/;                        // 匹配： {{value}} 中的 value
        let res = this.originText.match(regexAll);          // 匹配结果数组 [{{value}}，{{value}}，{{value}}]
        if (res == null) return '';                         // 未匹配到文本
        let str = this.originText;                          // 原始字符串模板 "name:{{0}} 或 name:{{0:fix2}}"

        for (let i = 0; i < res.length; i++) {
            const e = res[i];
            let getValue;
            let arr = e.match(regex);                       // 匹配到的数组 [{{value}}, value]
            let indexNum = parseInt(arr![1] || '0') || 0;   // 取出数组的 value 元素 转换成整数
            let format = this.templateFormatArr[i];         // 格式化字符 的 配置参数
            getValue = this.templateValueArr[indexNum];
            str = str.replace(e, this.getValueFromFormat(getValue, format));//从路径缓存值获取数据
        }
        return str;
    }

    /** 格式化字符串 */
    getValueFromFormat(value: number | string, format: string): string {
        return StringFormatFunction.deal(value, format);
    }

    /** 初始化获取数据 */
    onValueInit() {
        //更新信息
        if (this.templateMode === false) {
            this.setLabelValue(this.VM.getValue(this.watchPath)); //
        }
        else {
            let max = this.watchPathArr.length;
            for (let i = 0; i < max; i++) {
                this.templateValueArr[i] = this.VM.getValue(this.watchPathArr[i], '?');
            }
            this.setLabelValue(this.getReplaceText()); // 重新解析
        }
    }

    /** 监听数据发生了变动的情况 */
    onValueChanged(n: any, o: any, pathArr: string[]) {
        if (this.templateMode === false) {
            this.setLabelValue(n);
        }
        else {
            let path = pathArr.join('.');
            // 寻找缓存位置
            let index = this.watchPathArr.findIndex(v => v === path);

            if (index >= 0) {
                //如果是所属的路径，就可以替换文本了
                this.templateValueArr[index] = n;          // 缓存值
                this.setLabelValue(this.getReplaceText()); // 重新解析文本
            }
        }
    }

    setLabelValue(value: string) {
        var component: any = this.getComponent(this.labelType);
        component.string = value + '';
    }

    getLabelValue(): string {
        var component: any = this.getComponent(this.labelType);
        return component.string;
    }

    private checkLabel() {
        let checkArray = [
            'cc.Label',
            'cc.RichText',
            'cc.EditBox',
        ];

        for (let i = 0; i < checkArray.length; i++) {
            const e = checkArray[i];
            let comp = this.node.getComponent(e);
            if (comp) {
                this.labelType = e;
                return true;
            }
        }

        error('没有挂载任何label组件');

        return false;
    }
}