import { Vue, Component, Prop, Emit, Watch } from 'vue-property-decorator';
import { debounce } from '@ibizstudio/runtime';
import { ParameterDefinitionItem } from './parameter-definition-interface';
import './parameter-definition.less';

/**
 * 参数定义组件
 *
 * @export
 * @class ParameterDefinition
 * @extends {Vue}
 */
@Component({})
export class ParameterDefinition extends Vue {
  /**
   * 是否自定义编写参数
   *
   * @protected
   * @type {boolean}
   * @memberof ParameterDefinition
   */
  protected isCustom: boolean = false;

  /**
   * 值
   *
   * @protected
   * @type {string}
   * @memberof ParameterDefinition
   */
  protected $value: string = '';

  /**
   * 值内容
   *
   * @type {string}
   * @memberof ParameterDefinition
   */
  @Prop({ default: '' })
  public value!: string;

  /**
   * 监控值变化
   *
   * @memberof ParameterDefinition
   */
  @Watch('value', { deep: true, immediate: true })
  public watchValue(): void {
    if (!Object.is(this.value, this.$value)) {
      this.$value = this.value;
      this.dataFormat();
    }
  }

  /**
   * 分隔符
   *
   * @type {string}
   * @memberof ParameterDefinition
   */
  @Prop({ default: '\n' })
  public separator!: string;

  /**
   * 所有定义参数
   *
   * @protected
   * @type {ParameterDefinitionItem[]}
   * @memberof ParameterDefinition
   */
  protected items: ParameterDefinitionItem[] = [];

  /**
   * 参数类型
   *
   * @protected
   * @memberof ParameterDefinition
   */
  protected paramTypes: any = {
    default: {
      key: 'default',
      text: '默认',
    },
    context: {
      key: 'context',
      text: '上下文',
    },
    viewParam: {
      key: 'view',
      text: '视图参数',
    },
  };

  /**
   * 值类型
   *
   * @protected
   * @type {*}
   * @memberof ParameterDefinition
   */
  protected valTypes: any = {
    direct: {
      key: 'direct',
      text: '直接值',
    },
    context_view: {
      key: 'context_view',
      text: '值填充',
      regExp: /^%(.*)%$/,
    },
  };

  /**
   * 数据变更事件
   *
   * @param {string} val
   * @memberof ParameterDefinition
   */
  @Emit('data-change')
  public dataChange(val: string | null): void {}

  /**
   * 参数类型拼接
   *
   * @protected
   * @memberof ParameterDefinition
   */
  protected types = {
    // 上下文模式
    srfNavCtx: 'SRFNAVCTX',
    // 视图参数
    srfNavParam: 'SRFNAVPARAM',
  };

  time: any = null;

  /**
   * 值变更
   *
   * @protected
   * @memberof ParameterDefinition
   */
  protected change(): void {
    if (this.time) {
      clearTimeout(this.time);
      this.time = null;
    }
    this.time = setTimeout(() => {
      this.$value = this.changeFormat();
      const valueData = this.$value === '' ? null : this.$value;
      this.dataChange(valueData);
    }, 500);
  }

  /**
   * 参数格式化
   *
   * @protected
   * @param {string} [str=this.$value]
   * @memberof ParameterDefinition
   */
  protected dataFormat(str: string = this.$value): void {
    if (str && str !== '') {
      this.items = [];
      const items: string[] = str.split(this.separator);
      items.forEach((item: string) => {
        const arr: string[] = item.split('=');
        if (arr.length !== 2) {
          console.warn('解析失败，参数格式异常：' + item);
          return;
        }
        let valStr: string = arr[1];
        const valueType = this.valTypes.context_view.regExp.test(valStr) ? 'context_view' : 'direct';
        if (Object.is(valueType, 'context_view')) {
          valStr = valStr.replace(/%/g, '');
        }
        let keyStr = arr[0];
        let type = this.paramTypes.default.key;
        if (item.indexOf(this.types.srfNavCtx + '.') !== -1) {
          type = this.paramTypes.context.key;
          keyStr = arr[0].split('.')[1];
        } else if (item.indexOf(this.types.srfNavParam + '.') !== -1) {
          type = this.paramTypes.viewParam.key;
          keyStr = arr[0].split('.')[1];
        }
        this.items.push({
          type,
          valueType,
          keyStr,
          valStr,
        });
      });
    }
  }

  /**
   * 数据变更格式化
   *
   * @protected
   * @param {ParameterDefinitionItem[]} [items=this.items]
   * @returns {string}
   * @memberof ParameterDefinition
   */
  protected changeFormat(items: ParameterDefinitionItem[] = this.items): string {
    const arr = items.map((item: ParameterDefinitionItem) => {
      let str: string = '';
      switch (item.type) {
        case 'context':
          str += this.types.srfNavCtx + '.';
          break;
        case 'view':
          str += this.types.srfNavParam + '.';
          break;
      }
      return `${str}${item.keyStr}=${Object.is(item.valueType, 'direct') ? item.valStr : `%${item.valStr}%`}`;
    });
    return arr.join(this.separator);
  }

  /**
   * 拷贝相
   *
   * @protected
   * @param {*} item
   * @param {number} i
   * @memberof ParameterDefinition
   */
  protected copyItem(item: any, i: number): void {
    this.items.splice(i, 0, { ...item });
  }

  /**
   * 删除项
   *
   * @protected
   * @param {number} i
   * @memberof ParameterDefinition
   */
  protected removeItem(i: number): void {
    this.items.splice(i, 1);
    this.change();
  }

  /**
   * 添加项
   *
   * @protected
   * @memberof ParameterDefinition
   */
  protected addItem(): void {
    this.items.push({
      type: 'default',
      valueType: 'direct',
      keyStr: '',
      valStr: '',
    });
  }

  /**
   * 切换展示模式
   *
   * @protected
   * @memberof ParameterDefinition
   */
  protected changeShowMode(): void {
    if (this.isCustom) {
      this.dataFormat();
    } else {
      this.$value = this.changeFormat();
    }
    this.isCustom = !this.isCustom;
  }

  /**
   * 绘制项
   *
   * @protected
   * @param {ParameterDefinitionItem} item
   * @param {number} i
   * @returns {*}
   * @memberof ParameterDefinition
   */
  protected renderItem(item: ParameterDefinitionItem, i: number): any {
    const arr: any[] = [];
    for (const key in this.paramTypes) {
      const element = this.paramTypes[key];
      arr.push(
        <i-option value={element.key} key={element.key}>
          {element.text}
        </i-option>,
      );
    }
    const arr2: any[] = [];
    for (const key in this.valTypes) {
      const element = this.valTypes[key];
      arr2.push(
        <i-option value={element.key} key={element.key}>
          {element.text}
        </i-option>,
      );
    }
    return (
      <div class='param-item'>
        <div class='item item-type'>
          <i-select on-on-change={() => this.change()} v-model={item.type} size='small'>
            {arr}
          </i-select>
        </div>
        <div class='item item-key'>
          <i-input on-on-change={() => this.change()} v-model={item.keyStr} size='small' placeholder='请输入' />
        </div>
        <div class='item item-value'>
          <i-input on-on-change={() => this.change()} v-model={item.valStr} size='small' placeholder='请输入' />
        </div>
        <div class='item item-value-type'>
          <i-select on-on-change={() => this.change()} v-model={item.valueType} size='small'>
            {arr2}
          </i-select>
        </div>
        <div class='item remove' on-click={() => this.removeItem(i)}>
          <icon type='md-close' />
        </div>
        <div class='item copy' on-click={() => this.copyItem(item, i)}>
          <icon type='md-copy' />
        </div>
      </div>
    );
  }

  /**
   * 绘制内容
   *
   * @returns {*}
   * @memberof ParameterDefinition
   */
  public render(): any {
    return (
      <div class='parameter-definition'>
        {this.isCustom ? (
          <textarea class='ivu-input' rows={10} v-model={this.$value} on-change={() => this.dataChange(this.$value)} style='height:100px;'></textarea>
        ) : (
          <div class='param-items'>{this.items.map((item: any, i: number) => this.renderItem(item, i))}</div>
        )}
        <div class='param-add'>
          <i-button size='small' type='default' on-click={() => this.changeShowMode()}>
            {this.isCustom ? '关闭' : '开启'}自定义
          </i-button>
          {this.isCustom ? null : <i-button size='small' type='default' icon='md-add' on-click={() => this.addItem()} />}
        </div>
      </div>
    );
  }
}
