<template>
  <div class="transfer-container">
    <div class="transfer-modal">
      <div class="transfer-header">
        <span class="transfer-title">{{ title }}</span>
        <span
          class="transfer-close"
          @click="onClose"
        >×</span>
      </div>

      <div class="transfer-content">
        <div class="transfer-panel source-panel">
          <div class="panel-header">
            <div class="panel-header-inner">
              <span class="checkbox-wrapper">
                <input
                  ref="allCheckbox"
                  type="checkbox"
                  :checked="isAllSourceChecked"
                  :indeterminate="isIndeterminate"
                  @change="toggleAllSource"
                >
                <span :class="{'checkbox-label': true, 'checkbox-select': sourceCheckedCount }">{{ sourceCheckedCount }}/{{ sourceData.length }} 项</span>
              </span>
            </div>
          </div>

          <div class="panel-search">
            <input
              v-model="sourceSearchText"
              type="text"
              placeholder="请输入搜索内容"
            >
            <span class="search-icon">⌕</span>
          </div>

          <div class="panel-body">
            <div
              v-for="(item, index) in filteredSourceData"
              :key="'source-' + item.value"
              class="panel-item"
            >
              <label class="checkbox-item">
                <input
                  type="checkbox"
                  :checked="item.checked"
                  @change="toggleItem(item)"
                >
                <span :class="{'item-label': true, 'item-select': item.checked}">{{ item.label }}</span>
              </label>
            </div>
          </div>

          <div class="panel-footer">
            <button
              class="btn-reset"
              @click="resetToPreset"
            >重置</button>
          </div>
        </div>

        <div class="transfer-panel target-panel">
          <div class="panel-header">
            <div class="panel-header-inner">
              <span>已选 {{ displayTargetData.length }} 项</span>
              <button
                class="btn-clear"
                @click="clearTarget"
              >全部清空</button>
            </div>
          </div>

          <div class="panel-body">
            <div
              v-for="(item, index) in displayTargetData"
              :key="'target-' + item.value"
              class="panel-item"
            >
              <span class="item-icon">⋮⋮</span>
              <span class="item-label">{{ item.label }}</span>
              <span
                class="item-remove"
                @click="removeItem(item)"
              >×</span>
            </div>
          </div>
        </div>
      </div>

      <div class="transfer-footer">
        <button
          class="btn-cancel"
          @click="onClose"
        >取消</button>
        <button
          class="btn-confirm"
          @click="onConfirm"
        >确定</button>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'TransferList',
  props: {
    title: {
      type: String,
      default: '',
    },
    value: {
      type: Array,
      default: () => [],
    },
    data: {
      type: Array,
      default: () => [],
    },
    presetSelected: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      sourceData: [],
      targetData: [],
      sourceSearchText: '',
    };
  },
  computed: {
    filteredSourceData() {
      if (!this.sourceSearchText) {
        return this.sourceData;
      }
      return this.sourceData.filter(item =>
        item.label.toLowerCase().includes(this.sourceSearchText.toLowerCase()),
      );
    },
    sourceCheckedCount() {
      return this.sourceData.filter(item => item.checked).length;
    },
    isAllSourceChecked() {
      return this.sourceData.length > 0 && this.sourceData.every(item => item.checked);
    },
    isIndeterminate() {
      const checkedCount = this.sourceCheckedCount;
      return checkedCount > 0 && checkedCount < this.sourceData.length;
    },
    displayTargetData() {
      const checkedSourceItems = this.sourceData
        .filter(item => item.checked)
        .map(item => ({ ...item, fromSource: true }));

      const targetKeys = this.targetData.map(item => item.value);
      const uniqueCheckedItems = checkedSourceItems.filter(item => !targetKeys.includes(item.value));

      return [...this.targetData, ...uniqueCheckedItems];
    },
  },
  watch: {
    data: {
      immediate: true,
      handler() {
        this.initData();
      },
    },
    isIndeterminate: {
      handler(val) {
        if (this.$refs.allCheckbox) {
          this.$refs.allCheckbox.indeterminate = val;
        }
      },
    },
  },
  mounted() {
    if (this.$refs.allCheckbox) {
      this.$refs.allCheckbox.indeterminate = this.isIndeterminate;
    }
  },
  updated() {
    if (this.$refs.allCheckbox) {
      this.$refs.allCheckbox.indeterminate = this.isIndeterminate;
    }
  },
  methods: {
    initData() {
      const selectedKeys = this.value && this.value.length ? this.value : this.presetSelected || [];

      this.targetData = this.data
        .filter(item => selectedKeys.includes(item.value))
        .map(item => ({ ...item }));

      this.sourceData = this.data.map(item => ({
        ...item,
        checked: selectedKeys.includes(item.value),
      }));
    },
    toggleItem(item) {
      item.checked = !item.checked;
      this.syncTargetWithChecked();
      this.emitChange();
    },
    toggleAllSource() {
      const newCheckedState = !this.isAllSourceChecked;

      this.sourceData.forEach(item => {
        item.checked = newCheckedState;
      });

      this.syncTargetWithChecked();
      this.emitChange();
    },
    syncTargetWithChecked() {
      const checkedKeys = this.sourceData
        .filter(item => item.checked)
        .map(item => item.value);

      this.targetData = this.data
        .filter(item => checkedKeys.includes(item.value))
        .map(item => ({ ...item }));
    },
    resetToPreset() {
      const presetKeys = this.presetSelected || [];

      this.sourceData.forEach(item => {
        item.checked = presetKeys.includes(item.value);
      });

      this.targetData = this.data
        .filter(item => presetKeys.includes(item.value))
        .map(item => ({ ...item }));

      this.sourceSearchText = '';
      this.emitChange();
    },
    clearTarget() {
      this.targetData = [];

      this.sourceData.forEach(item => {
        item.checked = false;
      });

      this.emitChange();
    },
    removeItem(item) {
      const sourceItem = this.sourceData.find(sourceItem => sourceItem.value === item.value);
      if (sourceItem) {
        sourceItem.checked = false;
      }

      const targetIndex = this.targetData.findIndex(targetItem => targetItem.value === item.value);
      if (targetIndex !== -1) {
        this.targetData.splice(targetIndex, 1);
      }

      this.emitChange();
    },
    emitChange() {
      const selectedKeys = [];
      const selectedLabels = [];
      this.targetData.forEach(item => {
        selectedKeys.push(item.value);
        selectedLabels.push(item.label);
      });
      this.$emit('input', selectedKeys, selectedLabels);
      this.$emit('change', selectedKeys, selectedLabels);
    },
    onConfirm() {
      this.syncTargetWithChecked();
      this.$emit('confirm', this.targetData.map(item => item.value));
    },
    onClose() {
      this.$emit('cancel');
    },
  },
};
</script>

<style lang="scss" scoped>
.transfer-container {
  // 预留 css variables
  --primary-color: #6AB2FF;
  --bg-color: #151e2e;
  --text-color: rgb(255, 255, 255, 0.9);
  --border-color: #434343;
  --item-hover-bg: #262626;
  --panel-bg: #1f1f1f;
  --button-primary-bg: #3389FF;
  --button-primary-color: rgb(255, 255, 255, 0.9);
  --button-default-bg: #151e2e;
  --button-default-color: rgb(255, 255, 255, 0.7);
  --modal-bg: #1f1f1f;
  --modal-header-bg: #141414;
  --checkbox-color: #177ddc;
  --select-text-color: #6AB2FF;
}

.transfer {
  &-container {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(0, 0, 0, 0.5);
    z-index: 999;
  }

  &-modal {
    width: 700px;
    background-color: var(--modal-bg);
    display: flex;
    flex-direction: column;
    overflow: hidden;

    border-radius: 4px;
    border: 1px solid rgba(255, 255, 255, 0.07);
    box-shadow: 0px 8px 16px -8px rgba(0, 0, 0, 0.13), 0px 12px 32px rgba(0, 0, 0, 0.13), 0px 16px 48px rgba(0, 0, 0, 0.2);
    background-color: rgba(20, 29, 40, 1);
  }

  &-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 9px 16px;
  }

  &-title {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-color);
  }

  &-close {
    font-size: 22px;
    color: var(--text-color);
    opacity: 0.7;
    cursor: pointer;

    &:hover {
      opacity: 1;
    }
  }

  &-content {
    display: flex;
    padding: 16px;
    gap: 12px;

    font-size: 12px;
  }

  &-panel {
    flex: 1;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--border-color);
    border-radius: 4px;
    height: 490px;
  }

  &-footer {
    padding: 10px 16px;
    display: flex;
    justify-content: flex-end;
    gap: 8px;
  }
}

.panel {
  &-header {
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-color);

    &-inner {
      display: flex;
      justify-content: space-between;
      align-items: center;
      color: var(--text-color);
    }
  }

  &-search {
    padding: 8px 12px;
    position: relative;
    border-bottom: 1px solid var(--border-color);

    input {
      width: 100%;
      box-sizing: border-box;
      padding: 8px 12px;
      padding-right: 30px;
      border: 1px solid var(--border-color);
      border-radius: 4px;
      background-color: var(--bg-color);
      color: var(--text-color);
    }
  }

  &-body {
    flex: 1;
    overflow-y: auto;
    padding: 8px 0;
  }

  &-item {
    padding: 8px 12px;
    display: flex;
    align-items: center;
    cursor: pointer;

    &:hover {
      background-color: var(--item-hover-bg);
    }
  }

  &-footer {
    padding: 8px 12px;
    display: flex;
    justify-content: flex-start;
  }
}

.search-icon {
  position: absolute;
  right: 20px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 18px;
  color: var(--text-color);
  opacity: 0.5;
}

.checkbox {
  &-item {
    display: flex;
    align-items: center;
    width: 100%;
    cursor: pointer;
  }

  &-wrapper {
    display: flex;
    align-items: center;
  }

  &-label {
    margin-left: 8px;
    color: var(--text-color);
    text-align: left;
  }

  &-select {
    color: var(--select-text-color);
  }
}

.item {
  &-icon {
    margin-right: 8px;
    color: var(--text-color);
    opacity: 0.5;
  }

  &-label {
    flex: 1;
    margin-left: 8px;
    color: var(--text-color);
    text-align: left;
  }

  &-remove {
    color: var(--text-color);
    opacity: 0.7;
    cursor: pointer;
    font-size: 12px;

    &:hover {
      opacity: 1;
    }
  }
  &-select {
    color: var(--select-text-color);
  }
}

input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--checkbox-color);
  cursor: pointer;
}

.btn {
  &-reset, &-cancel {
    padding: 5px 16px;
    border: 1px solid var(--border-color);
    border-radius: 4px;
    background-color: var(--button-default-bg);
    color: var(--button-default-color);
    cursor: pointer;
  }

  &-clear {
    background: none;
    border: none;
    color: var(--primary-color);
    cursor: pointer;
    font-size: 12px;
    padding: 0;
    margin: 0;
  }

  &-confirm {
    padding: 5px 16px;
    border: none;
    border-radius: 4px;
    background-color: var(--button-primary-bg);
    color: var(--button-primary-color);
    cursor: pointer;
  }
}
</style>
