import { Component, Model, Prop, Vue, Inject } from 'vue-property-decorator';
import { CodeListService } from '@ibizstudio/runtime';
import { LogUtil, Util } from '@ibizstudio/runtime';
import { Subject, Subscription } from 'rxjs';
import { VueLifeCycleProcessing } from '../../../decorators';
import { calcEditorDropdownWidth } from '../utils';
import './tree-dropdown-list.less';
/**
 * 树形代码表插件类
 *
 * @export
 * @class TreeDropdownList
 * @extends {Vue}
 */
@Component({})
@VueLifeCycleProcessing()
export default class TreeDropdownList extends Vue {
  /**
   * 当前选中值
   * @type {any}
   * @memberof TreeDropdownList
   */
  @Model('change') readonly itemValue!: any;
  /**
   * 代码表标识
   *
   * @type {string}
   * @memberof TreeDropdownList
   */
  @Prop() tag?: string;

  /**
   * 代码表类型
   *
   * @type {string}
   * @memberof TreeDropdownList
   */
  @Prop() codelistType?: string;

  /**
   * 代码表
   *
   * @type {string}
   * @memberof TreeDropdownList
   */

  @Prop() codeList!: any;

  /**
   * 传入表单数据
   *
   * @type {*}
   * @memberof TreeDropdownList
   */
  @Prop() data?: any;

  /**
   * @description 表单状态对象
   * @type {Subject<any>}
   * @memberof TreeDropdownList
   */
   @Inject('formState')
   formState!: Subject<any>

  /**
   * 局部上下文导航参数
   *
   * @type {*}
   * @memberof TreeDropdownList
   */
  @Prop() localContext!: any;

  /**
   * 局部导航参数
   *
   * @type {*}
   * @memberof TreeDropdownList
   */
  @Prop() localParam!: any;

  /**
   * @description 视图上下文
   * @type {*}
   * @memberof TreeDropdownList
   */
  @Prop() declare context: any;

  /**
   * @description 视图参数
   * @type {*}
   * @memberof TreeDropdownList
   */
  @Prop() declare viewparams: any;

  /**
   * 是否禁用
   * @type {any}
   * @memberof TreeDropdownList
   *
   */
  @Prop() disabled?: any;

  /**
   * @description 只读模式
   * @type {boolean}
   * @memberof TreeDropdownList
   */
  @Prop({ default: false }) readonly?: boolean;

  /**
   * 下拉选提示内容
   * @type {string}
   * @memberof TreeDropdownList
   */
  @Prop() placeholder?: string;

  /**
   * 属性类型
   *
   * @type {'string' | 'number'}
   * @memberof TreeDropdownList
   */
  @Prop({ default: 'string' })
  valueType!: 'string' | 'number';

  /**
   * 代码表值分隔符
   *
   * @type {string}
   * @memberof TreeDropdownList
   */
  @Prop({ default: ',' }) valueSeparator!: string;

  /**
   * @description 是否多选
   * @type {boolean}
   * @memberof TreeDropdownList
   */
  @Prop({ default: false })
  isMultiple!: boolean;

  /**
   * 代码表服务对象
   *
   * @type {CodeListService}
   * @memberof TreeDropdownList
   */
  codeListService: CodeListService = new CodeListService({ $store: this.$store });

  /**
   * 是否有子集
   * @type {boolean}
   * @memberof TreeDropdownList
   */
  hasChildren: boolean = false;

  /**
   * @description 过滤词
   * @memberof TreeDropdownList
   */
  searchValue: string = '';

  /**
   * @description 选中数据
   * @type {*}
   * @memberof TreeDropdownList
   */
  select: any = null;

  /**
   * 代码表
   *
   * @type {any[]}
   * @memberof TreeDropdownList
   */
  items: any[] = [];

  /**
   * @description 临时代码表
   * @type {any[]}
   * @memberof TreeDropdownList
   */
  codeListData: any[] = [];

  /**
   * @description 订阅对象
   * @protected
   * @type {(Subscription | undefined)}
   * @memberof TreeDropdownList
   */
  protected formStateEvent: Subscription | undefined;

  isSpread: boolean = false;

  /**
   * @description 获取值
   * @memberof TreeDropdownList
   */
  get currentVal() {
    if (this.itemValue) {
      return this.itemValue.split(this.valueSeparator);
    } else {
      return [];
    }
  }

  /**
   * @description 获取值
   * @memberof TreeDropdownList
   */
  set currentVal($event: any[]) {
    const string = $event.join(this.valueSeparator);
    this.$emit('change', string ? string : null);
  }

  /**
   * @description 当前单选输入值
   * @memberof TreeDropdownList
   */
  get curText() {
    if (this.select && Object.is(this.select.value, this.itemValue)) {
      return this.select.label;
    } else {
      const item = this.codeListData.find(data => Object.is(data.value, this.itemValue));
      if (item) {
        this.select = item;
        return item.label;
      } else {
        return this.searchValue;
      }
    }
  }

  /**
   * @description 当前单选输入值
   * @memberof TreeDropdownList
   */
  set curText(value: string) {
    const autoComplete = this.$refs.autoComplete as Vue;
    const el = (autoComplete?.$refs?.input as Vue)?.$refs?.input;
    if (el && el === document.activeElement) {
      this.searchValue = value;
    } else {
      this.searchValue = '';
    }
    const item = this.codeListData.find(data => Object.is(data.label, value));
    if (item) {
      this.select = item;
      this.$emit('change', item.value);
    } else {
      this.$emit('change', value);
    }
  }

  /**
   * vue  生命周期
   *
   * @memberof TreeDropdownList
   */
  created() {
    if (this.formState) {
      this.formStateEvent = this.formState.subscribe(({ type, data }) => {
        if (Object.is('load', type)) {
          this.handleCodeListItems();
        }
      });
    }
    if (this.itemValue || this.itemValue === 0 || this.itemValue === false) {
      this.handleCodeListItems();
    }
  }

  /**
   * 选项行样式名
   *
   * @type {string}
   * @memberof DropDownList
   */

  itemClass: string = '';

  /**
   * 选项组样式名
   *
   * @type {string}
   * @memberof DropDownList
   */

  transferClass: string = 'transferDropdownWidthTreeDropdowmList';

  /**
   * @description 生命周期
   * @memberof TreeDropdownList
   */
  destroyed() {
    if (this.formStateEvent) {
      this.formStateEvent.unsubscribe();
    }
  }

  /**
   * @description 下拉显示控制
   * @param {boolean} visible
   * @memberof TreeDropdownList
   */
  visibleChange(visible: boolean) {
    this.isSpread = true;
    if (visible) {
      const dropdownSelect = this.$refs.dropdownSelect as Vue;
      if (dropdownSelect) {
        const popper = dropdownSelect.$refs.popper as Vue;
        if (popper) {
          const popperEl = popper.$el as HTMLElement;
          const el = this.$el as HTMLElement;
          if (popperEl && el) {
            popperEl.style.minWidth = `${el.offsetWidth}px`;
            popperEl.style.maxWidth = `${el.offsetWidth > 700 ? el.offsetWidth : 700}px`;
          }
        }
      }
      const autoComplete = this.$refs.autoComplete as Vue;
      if (autoComplete) {
        const select = autoComplete.$refs.select as Vue;
        if (select) {
          const dropdown = select.$refs.dropdown as Vue;
          if (dropdown) {
            const dropdownEl = dropdown.$el as HTMLElement;
            const el = this.$el as HTMLElement;
            if (dropdownEl && el) {
              dropdownEl.style.minWidth = `${el.offsetWidth}px`;
              dropdownEl.style.maxWidth = `${el.offsetWidth > 700 ? el.offsetWidth : 700}px`;
            }
          }
        }
      }
      this.handleCodeListItems();
    }
  }

  /**
   * 处理代码表
   *
   * @memberof TreeDropdownList
   */
  handleCodeListItems() {
    if (this.tag && this.codelistType) {
      let data: any = {};
      this.handlePublicParams(data);
      // 参数处理
      let context = data.context;
      let viewparam = data.param;
      this.codeListService
        .getDataItems({ tag: this.tag, type: this.codelistType, data: this.codeList, context: context, viewparam: viewparam })
        .then((codelistItems: Array<any>) => {
          this.codeListData = codelistItems;
          this.formatCodeList(codelistItems);
        })
        .catch((error: any) => {
          LogUtil.log(`----${this.tag}----${this.$t('app.commonwords.codenotexist') as string}`);
        });
    }
  }

  /**
   * @description 公共参数处理
   * @param {*} arg
   * @memberof TreeDropdownList
   */
  handlePublicParams(arg: any) {
    // 合并表单参数
    arg.param = this.viewparams ? JSON.parse(JSON.stringify(this.viewparams)) : {};
    arg.context = this.context ? JSON.parse(JSON.stringify(this.context)) : {};
    // 附加参数处理
    if (this.localContext && Object.keys(this.localContext).length > 0) {
      let _context = this.$util.computedNavData(this.data, arg.context, arg.param, this.localContext);
      Object.assign(arg.context, _context);
    }
    if (this.localParam && Object.keys(this.localParam).length > 0) {
      let _param = this.$util.computedNavData(this.data, arg.context, arg.param, this.localParam);
      Object.assign(arg.param, _param);
    }
  }

  /**
   * 代码表类型和属性匹配
   *
   * @param {*} items
   * @memberof TreeDropdownList
   */
  formatCodeList(items: Array<any>) {
    let matching: boolean = false;
    this.items = [];
    try {
      items.forEach((item: any) => {
        const type = this.$util.typeOf(item.value);
        if (type != this.valueType) {
          matching = true;
          if (type === 'number') {
            item.value = item.value.toString();
          } else {
            if (type == 'null') {
              this.valueType == 'number' ? (item.value = 0) : (item.value = '');
            } else if (item.value.indexOf('.') == -1) {
              item.value = parseInt(item.value);
            } else {
              item.value = parseFloat(item.value);
            }
          }
        }
        this.items.push(item);
      });
      if (matching) {
        LogUtil.warn(`${this.tag}${this.$t('app.commonwords.codelistwarn')}`);
      }
    } catch (error) {
      LogUtil.warn(this.$t('app.commonwords.codelistwarn'));
    }
    this.handleLevelCodeList(Util.deepCopy(this.items));
  }

  /**
   * 处理层级代码表
   *
   * @param {*} items
   * @memberof TreeDropdownList
   */
  handleLevelCodeList(items: Array<any>) {
    if (items && items.length > 0) {
      this.hasChildren = items.some((item: any) => {
        return item.pvalue;
      });
      if (this.hasChildren) {
        let list: Array<any> = [];
        items.forEach((codeItem: any) => {
          if (!codeItem.pvalue) {
            let valueField: string = codeItem.value;
            this.setChildCodeItems(valueField, items, codeItem);
            list.push(codeItem);
          }
        });
        this.items = list;
      }
    }
  }

  /**
   * 计算子类代码表
   *
   * @param {*} items
   * @memberof TreeDropdownList
   */
  setChildCodeItems(pValue: string, result: Array<any>, codeItem: any) {
    result.forEach((item: any) => {
      if (item.pvalue == pValue) {
        let valueField: string = item.value;
        this.setChildCodeItems(valueField, result, item);
        if (!codeItem.children) {
          codeItem.children = [];
        }
        codeItem.children.push(item);
      }
    });
  }

  /**
   * @description 对数据进行过滤,判断当前项是否显示
   * @param {*} data
   * @param {*} pItems
   * @return {*}
   * @memberof TreeDropdownList
   */
  isShow(data: any, pItem: any): boolean {
    if (Object.is(this.searchValue, '')) {
      return true;
    }
    if (data.text.indexOf(this.searchValue) > -1) {
      return true;
    } else {
      if (data.children) {
        if (this.findChild(data.children)) {
          return true;
        }
      }
      if (pItem.text && pItem.text.indexOf(this.searchValue) > -1) {
        return true;
      }
    }
    return false;
  }

  /**
   * @description 查看子项是否有符合项
   * @param {*} data
   * @param {*} codelistItems
   * @param {*} word
   * @return {*}
   * @memberof TreeDropdownList
   */
  findChild(data: any[]) {
    const index: number = data.findIndex((item: any) => {
      if (item.text.indexOf(this.searchValue) > -1) {
        return true;
      } else if (item.children) {
        return this.findChild(item.children);
      }
    });
    return Object.is(index, -1) ? false : true;
  }

  /**
   * @description 生成树形代码表-下拉单选
   * @param {*} items
   * @memberof TreeDropdownList
   */
  setTreeDropdownList(item: any, pItem: any = {}) {
    const isShow: boolean = this.isShow(item, pItem);
    if (item.children) {
      return isShow ? (
        <div>
          <div class='dropdowm-list-group'>
            <span>{item.label}</span>
          </div>
          <div class='tree-dropdowm-list-content'>
            {item.children.map((item: any) => {
              return this.setTreeDropdownList(item, item);
            })}
          </div>
        </div>
      ) : null;
    } else {
      return isShow ? (
        <i-option class={[{ 'option-active': Object.is(item.value, this.itemValue) }, this.itemClass]} key={item.value} value={item.label}>
          <span>{item.label}</span>
        </i-option>
      ) : null;
    }
  }

  /**
   * @description 绘制多选下拉树形列表
   * @param {*} items
   * @return {*}
   * @memberof TreeDropdownList
   */
  setTreeDropdownListMultiple(item: any, pItem: any = {}) {
    const hidden = this.isShow(item, pItem);
    if (item.children) {
      return hidden ? (
        <el-option-group key={item.id} label={item.label}>
          {item.children.map((item: any) => {
            return this.setTreeDropdownListMultiple(item, item);
          })}
        </el-option-group>
      ) : null;
    } else {
      return hidden ? <el-option key={item.id} label={item.label} value={item.value}></el-option> : null;
    }
  }

  render() {
    if (this.isMultiple) {
      return (
        <div class='tree-dropdowm-list' ref='treeDropdownList'>
          <el-select
            ref='dropdownSelect'
            v-model={this.currentVal}
            size='small'
            popper-class='tree-dropdowm-list-option'
            multiple
            filterable
            allow-create
            on-visible-change={(visible: boolean) => this.visibleChange(visible)}
            default-first-option
            placeholder={this.placeholder}
          >
            {this.items.map((item: any) => {
              return this.setTreeDropdownListMultiple(item);
            })}
          </el-select>
        </div>
      );
    } else {
      return (
        <div class='tree-dropdowm-list' ref='treeDropdownList'>
          <auto-complete
            ref='autoComplete'
            class={this.isSpread ? 'select-visible' : ''}
            v-model={this.curText}
            transfer={true}
            transfer-class-name={this.transferClass}
            on-on-focus={() => this.visibleChange(true)}
            icon='ios-arrow-down'
            on-on-blur={() => {
              this.isSpread = false;
            }}
          >
            {this.items.map((item: any) => {
              return this.setTreeDropdownList(item);
            })}
          </auto-complete>
        </div>
      );
    }
  }
}
