<script>
import { Transfer, Tabs, Icon, Button, Modal } from 'ant-design-vue'
import uniqueArray from '@/common/services/unique-array'
import sdDraggableModal from '@/common/components/sd-draggable-modal'
import pickerMixinInternal from '@/common/components/sd-picker/picker-mixin-internal'
import pickerListRight from '@/common/components/sd-picker/sd-picker-list-right.vue'
import SdSelect from '@/common/components/sd-select.vue'
import components from './_import-components/audit-value-picker-import'

/**
 * input框，通过弹出对话框选择数据，支持列表、树等多种数据源
 * @displayName SdValuePicker 值选择器
 */
export default {
  name: 'AuditValuePicker',
  components,
  mixins: [pickerMixinInternal],
  props: {
    selectclick: {
      type: Function,
      default: null,
    },
    /**
     * 根节点{code:'200000',name:'西安分公司'}
     */
    rootNode: {
      type: [Object, Array],
      default: undefined,
    },
  },
  data() {
    return {
      activeTab: 0, // 当前激活的tab页
      pickerSources: [], // 各数据源的属性，如标题、图标等
      modalVisible: false,
      targetKeys: [], // 已经选到右边的key，
      dataSourceInTargetKeys: [], // 已经选到右边的key，每一项都保存一份数据源信息
      selectedKeys: [],
      dataSource: {},
      showSearch: {},
      searchValue: {},
    }
  },
  computed: {
    singleMode() {
      return this.single || this.singleColumn
    },
    keysToInput() {
      // 不管什么模式，最终将要写入Input框的keys
      return this.singleMode ? this.selectedKeys : this.targetKeys
    },
    dblClickMode() {
      // 单列模式不能使用点击移动
      return this.dblClickTransfer || this.singleMode
    },
    allDataSourceOriginal() {
      return this.allDataSource.map((item) => item.originalValue)
    },
    allDataSource() {
      const currentTabDataSource = this.dataSource[this.activeTab] || []
      // 当前tab页的数据源+已选中到右边的数据源
      return this.dataSourceInTargetKeys
        .filter(
          // 过滤掉已经在数据源里面的
          (item) =>
            !currentTabDataSource.find(
              (item2) => item[this.optionValue] === item2[this.optionValue]
            )
        )
        .concat(
          currentTabDataSource.filter(
            // 把disabledKeys中的数据源去掉
            (item) => this.disabledKeys.indexOf(item[this.optionValue]) === -1
          )
        )
        .map((item) => {
          return {
            key: item[this.optionValue],
            title: item[this.optionLabel],
            disabled: item.disabled === true,
            originalValue: item,
          }
        })
    },
    dataSourceRight() {
      // 已选中部分的数据源
      return this.targetKeys.map(
        (key) => this.allDataSource.find((item) => item.key === key).originalValue
      )
    },
  },
  watch: {
    targetKeys(keys) {
      // 已经选到右边的key，每一项都保存一份数据源信息
      const dataSource = keys.map((key) =>
        this.allDataSourceOriginal.find((data) => key === data[this.optionValue])
      )
      this.dataSourceInTargetKeys = dataSource
    },
  },
  mounted() {
    // 计算有几个数据源
    this.pickerSources = this.$scopedSlots
      .default()
      .filter((vnode) => !!vnode.componentOptions)
      .map((vnode) => {
        return {
          title: vnode.componentOptions.propsData.title,
          icon: vnode.componentOptions.propsData.icon,
        }
      })
  },

  methods: {
    change(keys, direction, moveKeys) {
      if (direction === 'right') {
        this.targetKeys = this.targetKeys.concat(moveKeys)
      } else {
        this.targetKeys = keys
      }
    },
    selectChange(keys) {
      // 单选模式，始终只选中一个
      if (this.single) {
        if (keys.length > 0) this.selectedKeys = [keys[keys.length - 1]]
      } else if (this.singleColumn) {
        this.selectedKeys = keys
      }
    },
    closeModal() {
      this.modalVisible = false
    },
    inputClick() {
      // 只读模式不弹窗，直接返回
      if (this.readOnly) return
      if (this.selectclick !== null) {
        this.selectclick()
      } else {
        this.$refs.select.blur()
        // 初始化各种选择器相关的数据
        this.activeTab = 0
        this.dataSource = {}
        this.dataSourceInTargetKeys = this.value
        this.showSearch = {}
        this.targetKeys = this.selectedKeys = this.keyInValue()
        if (this.rootNode !== undefined) {
          if (this.rootNode.id !== '') {
            this.modalVisible = true
          } else {
            let lx = ''
            if (this.rootNode.name.indexOf('内控') > -1) {
              lx = '内控'
            }else if(this.rootNode.name.indexOf('风控') > -1){
              lx = '风控'
            }
            Modal.info({
              content: '请配置组织对应的' + lx + '机构',
            })
          }
        } else {
          this.modalVisible = true
        }
      }
    },
    handleOk() {
      const keys = this.keysToInput
      const value = keys.map((key) => {
        return this.allDataSource.find((item) => item.key === key).originalValue
      })
      this.$emit('change', value)
      this.closeModal()
    },
    updateDataSource(data) {
      // 先把数组去重处理
      this.dataSource[this.activeTab] = uniqueArray(data, (item) => item[this.optionValue])
      this.dataSource = { ...this.dataSource }
    },
    updateShowSearch(data) {
      this.showSearch[this.activeTab] = data
      this.showSearch = { ...this.showSearch }
    },
    itemDblClick(evt, key, direction) {
      if (direction !== 'right') {
        if (this.single) {
          this.handleOk()
        } else {
          if (this.singleColumn) return
          this.targetKeys.push(key)
        }
      } else {
        this.targetKeys.splice(this.targetKeys.indexOf(key), 1)
      }
    },
    removeTargetKeyItem(key) {
      this.targetKeys.splice(this.targetKeys.indexOf(key), 1)
    },
    keyInValue() {
      return this.value ? this.value.map((v) => v[this.optionValue]) : []
    },
  },
  /**
   * input框最后的图标
   * @slot suffixIcon
   */
  /**
   * 选择器的数据源，可以是多个
   * @slot default
   * @binding scope {object} 各种值和工具函数，无需解析直接传递给内部的数据源即可
   */
  /**
   * 右侧列表顶部
   * <p>8.0.7 新增</p>
   * @slot targetListHeader
   * @binding targetKeys {array} 右侧列表所有项目的 key 值
   * @binding targetValues {array} 右侧列表所有项目的完整 Object 值
   */
  render(h) {
    const renderTransfer = (index) => {
      return (
        <div
          class={{ [this.$style.wrapper]: true, [this.$style.singleClickMode]: !this.dblClickMode }}
        >
          {this.singleMode || index !== this.activeTab ? (
            undefined
          ) : (
            <div class={this.$style.targetListHeader}>
              {this.$scopedSlots.targetListHeader?.({
                targetKeys: this.targetKeys,
                targetValues: this.dataSourceInTargetKeys,
              })}
              <Button
                icon='sd-trash2'
                type='link'
                title='全部删除'
                on={{
                  click: () => {
                    this.targetKeys = []
                  },
                }}
              ></Button>
            </div>
          )}
          {this.singleMode ? (
            undefined
          ) : (
            <div class={this.$style.sourceListHeader}>
              <Button
                icon='double-right'
                type='link'
                title='全部增加'
                on={{
                  click: () =>
                    this.allDataSource.forEach((item) => {
                      if (!this.targetKeys.includes(item.key)) {
                        this.targetKeys.push(item.key)
                      }
                    }),
                }}
              ></Button>
            </div>
          )}

          <Transfer
            class={[
              this.$style.transfer,
              {
                [this.$style.single]: this.singleMode,
                [this.$style.singleColumn]: this.singleColumn,
                [this.$style.showSearch]: !this.singleColumn && this.showSearch[this.activeTab],
              },
            ]}
            showSelectAll={!this.single}
            dataSource={this.allDataSource}
            targetKeys={this.singleMode ? undefined : this.targetKeys}
            selectedKeys={!this.singleMode ? undefined : this.selectedKeys}
            lazy={false}
            showSearch={true} // 用css隐藏搜索框，改prop的值会导致内部picker-source组件重新创建
            filterOption={() => true} // 不过滤任何数据，只是为了显示出搜索框来
            on={{
              change: this.change,
              search: (direction, value) => {
                if (direction === 'left') this.searchValue[index] = value
              },
              selectChange: this.selectChange,
            }}
            scopedSlots={{
              children: (scope) => {
                if (scope.props.direction !== 'left')
                  return (
                    <pickerListRight
                      itemSelect={
                        this.dblClickMode
                          ? scope.on.itemSelect
                          : (key, checked) => this.itemDblClick({}, key, 'right')
                      }
                      dataSource={this.dataSourceRight}
                      selectedKeys={scope.props.selectedKeys}
                      targetKeys={this.targetKeys}
                      itemDblClick={this.dblClickTransfer ? this.itemDblClick : () => {}}
                      render={this.render}
                      optionValue={this.optionValue}
                      optionLabel={this.optionLabel}
                      on={{
                        updateTargetKeys: (keys) => {
                          this.targetKeys = keys
                        },
                      }}
                    />
                  )

                return [
                  this.$scopedSlots
                    .default({
                      render: this.render,
                      single: this.single,
                      selectedKeys: scope.props.selectedKeys,
                      targetKeys: this.singleMode ? [] : this.targetKeys,
                      disabledKeys: this.disabledKeys,
                      itemSelect: this.dblClickMode
                        ? this.singleColumn
                          ? (...args) => {
                              // 单列多选模式时，对于selectedKeys的处理有些问题，加个timeout
                              setTimeout(() => scope.on.itemSelect(...args))
                            }
                          : scope.on.itemSelect
                        : (key, checked) => this.itemDblClick({}, key, 'left'),
                      updateDataSource: this.updateDataSource,
                      dataSource: index === this.activeTab ? this.allDataSourceOriginal : [],
                      itemDblClick: this.dblClickTransfer ? this.itemDblClick : () => {},
                      optionValue: this.optionValue,
                      optionLabel: this.optionLabel,
                      updateShowSearch: this.updateShowSearch,
                      searchValue: this.searchValue[index],
                    })
                    .filter((vnode) => !!vnode.componentOptions)[index],
                ]
              },
            }}
          ></Transfer>
        </div>
      )
    }
    return (
      <span
        class={{
          [this.$style.allowClear]: this.value?.length > 1,
          [this.$style.selectWrapper]: true,
        }}
      >
        <SdSelect
          ref='select'
          value={this.value}
          optionLabel={this.optionLabel}
          optionValue={this.optionValue}
          options={[]}
          open={false}
          readOnly={this.readOnly}
          mode='multiple'
          showArrow={false}
          on={{
            ...this.$listeners,
          }}
          nativeOnClick={this.inputClick}
        />
        {this.$scopedSlots.suffixIcon && !this.readOnly ? (
          <span class={this.$style.icon}>{this.$scopedSlots.suffixIcon()}</span>
        ) : (
          undefined
        )}
        <sdDraggableModal
          title={this.title}
          visible={this.modalVisible}
          destroyOnClose={true}
          width={
            this.modalProps.width ||
            (this.single ? 600 : 800) + (this.pickerSources.length > 1 ? 100 : 0)
          }
          okButtonProps={
            this.required && this.keysToInput.length === 0 ? { props: { disabled: true } } : {}
          }
          attrs={this.modalProps}
          on={{
            cancel: () => {
              this.closeModal()
              this.$emit('cancel')
            },
            ok: this.handleOk,
          }}
        >
          {this.pickerSources.length > 1 ? (
            <Tabs
              class={this.$style.tab}
              tabPosition='left'
              on={{ change: (tab) => (this.activeTab = tab) }}
            >
              {this.pickerSources.map((source, index) => {
                return (
                  <Tabs.TabPane key={index}>
                    <div slot='tab' class={this.$style.tabTitle}>
                      {source.icon ? <Icon type={source.icon} /> : undefined}
                      {source.title ? <div>{source.title}</div> : undefined}
                    </div>
                    {renderTransfer(index)}
                  </Tabs.TabPane>
                )
              })}
            </Tabs>
          ) : (
            renderTransfer(0)
          )}
        </sdDraggableModal>
      </span>
    )
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
.wrapper {
  position: relative;
}
.select-wrapper {
  position: relative;
  display: inline-block;
  width: 100%;
  :global .ant-select {
    padding: 4px 0; // 保持上下边距相等，目前还没弄清为什么必须要加padding
    vertical-align: middle;
    .ant-select-selection {
      max-height: 86px; // 最多显示三行
      overflow-y: auto;
      /* stylelint-disable-next-line */
      .ant-select-selection__clear {
        top: 50%;
      }
    }
  }
}
.allow-clear:hover {
  .icon {
    opacity: 0;
  }
}

.icon {
  position: absolute;
  top: 50%;
  right: 11px;
  margin-top: -$font-size-base / 2;
  line-height: $font-size-base;
  color: $disabled-color;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
.transfer {
  display: flex;
  :global .ant-transfer-list {
    flex: 1;
    height: 500px;
    .ant-transfer-list-body {
      display: flex;
      flex-direction: column;
    }
    .ant-transfer-list-body-search-wrapper {
      padding-bottom: 12px;
    }
    .ant-transfer-list-content-item {
      white-space: normal;
      user-select: none;
    }
    .ant-radio-wrapper {
      margin-right: 0;
    }
  }

  // 右侧待选区，不显示搜索框
  :global .ant-transfer-list:last-child {
    .ant-transfer-list-body-search-wrapper {
      display: none;
    }
  }

  &:not(.show-search) {
    :global .ant-transfer-list-body-search-wrapper {
      // display: none;
    }
  }
}
.tab {
  &:global(.ant-tabs .ant-tabs-left-bar .ant-tabs-tab) {
    padding: 8px 15px 8px 0;
    .tab-title {
      text-align: center;
      :global(.anticon) {
        margin-right: 0;
        font-size: $font-size-base * 1.5;
      }
    }
  }
}

.single {
  :global .ant-transfer-operation,
  :global .ant-transfer-list:last-child {
    display: none;
  }
  &:not(.single-column) {
    :global(.ant-transfer-list-header) {
      display: none;
    }
    :global .ant-transfer-list {
      padding-top: 0;
    }
  }
}

.list-text {
  display: inline-block;
  min-width: 200px;
}

.target-list-header {
  position: absolute;
  right: 0;
  z-index: 1;
  padding: 3px 0;
}

.source-list-header {
  position: absolute;
  left: 50%;
  z-index: 1;
  padding: 3px 0;
  margin-left: -52px;
}

.single-click-mode {
  :global(.ant-transfer-list-content .ant-checkbox-wrapper),
  :global(.ant-transfer-list-header .ant-checkbox-wrapper) {
    width: 0;
    margin-right: -8px;
    visibility: hidden;
  }
}
</style>
