import { ref, computed, watch, onMounted } from 'vue';
import type { SetupContext } from 'vue';
import { TTransferProps, IItem, TKey, IDargItemAndDropItem } from '../transfer-types';

export const transferState = (props: TTransferProps, ctx: SetupContext) => {
  const sourceTitle = computed(() => props.titles[0]);
  const targetTitle = computed(() => props.titles[1]);
  const sourceChecked = ref<TKey[]>([]);
  const targetChecked = ref<TKey[]>([]);
  const sourceData = ref<IItem[]>([]);
  const targetData = ref<IItem[]>([]);
  const sourceDirection = ref('source');
  const targetDirection = ref('target');
  const sourceDisabled = computed(() => {
    return targetChecked.value.length === 0;
  });
  const targetDisabled = computed(() => {
    return sourceChecked.value.length === 0;
  });
  const activeDirection = ref('source');
  const activeMoveItems = ref<IItem[]>([]);

  /**
   * getTransferData: 处理穿梭框数据
   */
  const getTransferData = () => {
    return {
      data: (() => {
        if (props.data && typeof props.sortMethods === 'function') {
          return props.sortMethods(props.data) ?? [];
        }
        return props.data;
      })(),
    };
  };
  /**
   * updateSourceAllCheckedHandle: 更新源穿梭框全选
   * @param value 是否全选
   */
  const updateSourceAllCheckedHandle = (value: TKey[]) => {
    sourceChecked.value = value;
  };
  /**
   * updateTargetAllCheckedHandle: 更新目标穿梭框全选
   * @param value 是否全选
   */
  const updateTargetAllCheckedHandle = (value: TKey[]) => {
    targetChecked.value = value;
  };
  /**
   * updateSourceCheckedHandle: 更新源选中值
   * @param value 是否可用
   */
  const updateSourceCheckedHandle = (value: TKey[]) => {
    sourceChecked.value = value;
  };
  /**
   * updateTargetCheckedHandle: 更新目标选中值
   * @param value 是否可用
   */
  const updateTargetCheckedHandle = (value: TKey[]) => {
    targetChecked.value = value;
  };
  const updateModelValue = () => {
    const targetValues = targetData.value.map((item) => {
      return item.value;
    });
    ctx.emit('update:modelValue', targetValues);
    ctx.emit('change', targetValues, activeDirection.value, activeMoveItems.value);
  };
  /**
   * toMoveTargetHandle: 源选中穿梭到目标
   */
  const toMoveTargetHandle = () => {
    const notIncluded: IItem[] = [];
    sourceData.value = sourceData.value.filter((item) => {
      if (!sourceChecked.value.includes(item.value)) {
        return true;
      }
      notIncluded.push(item);
      return false;
    });
    sourceChecked.value = [];
    targetData.value = targetData.value.concat(notIncluded);
    activeDirection.value = 'target';
    activeMoveItems.value = notIncluded;
  };
  /**
   * toMoveSourceHandle: 目标选中穿梭到源
   */
  const toMoveSourceHandle = () => {
    const notIncluded: IItem[] = [];
    targetData.value = targetData.value.filter((item) => {
      if (!targetChecked.value.includes(item.value)) {
        return true;
      }
      notIncluded.push(item);
      return false;
    });
    targetChecked.value = [];
    sourceData.value = sourceData.value.concat(notIncluded);
    activeDirection.value = 'source';
    activeMoveItems.value = notIncluded;
  };

  watch(targetData, () => {
    updateModelValue();
  });

  /**
   * getDargItemAndDropItem: 获取拖拽的item及放开的item
   * @param startValue 当前拖拽item的值
   * @param endValue 放开item的值
   * @param direction 穿梭框拖拽方向
   */
  const getDargItemAndDropItem = (startValue: TKey, endValue: TKey, direction: TKey): IDargItemAndDropItem => {
    const dataList: Array<IItem> = direction === 'source' ? sourceData.value : targetData.value;
    let startIndex = -1,
      endIndex = -1;
    let dragItem = null,
      dropItem = null;
    for (let i = 0; i < dataList.length; i++) {
      if (dataList[i].value === startValue) {
        startIndex = i;
        dragItem = dataList[i];
      }
      if (dataList[i].value === endValue) {
        endIndex = i;
        dropItem = dataList[i];
      }
    }
    return {
      startIndex,
      endIndex,
      dragItem: dragItem as IItem,
      dropItem: dropItem as IItem,
    };
  };
  /**
   * updateSourceDataHandle: 更新source数据
   * @param startValue 当前拖拽item的值
   * @param endValue 放开item的值
   */
  const updateSourceDataHandle = (startValue: TKey, endValue: TKey, position: number) => {
    const { startIndex, endIndex, dragItem } = getDargItemAndDropItem(startValue, endValue, 'source');
    let end = endIndex;
    if (position === 1) {
      end = endIndex + 1;
    }
    if (startIndex < end) {
      sourceData.value.splice(end, 0, dragItem);
      sourceData.value.splice(startIndex, 1);
    } else {
      sourceData.value.splice(startIndex, 1);
      sourceData.value.splice(end, 0, dragItem);
    }
    ctx.emit('sourceDragEnd', [...sourceData.value]);
  };
  /**
   * updateTargetDataHandle: 更新target数据
   * @param startValue 当前拖拽item的值
   * @param endValue 放开item的值
   */
  const updateTargetDataHandle = (startValue: TKey, endValue: TKey, position: number) => {
    const { startIndex, endIndex, dragItem } = getDargItemAndDropItem(startValue, endValue, 'target');
    let end = endIndex;
    if (position === 1) {
      end = endIndex + 1;
    }
    if (startIndex < end) {
      targetData.value.splice(end, 0, dragItem);
      targetData.value.splice(startIndex, 1);
    } else {
      targetData.value.splice(startIndex, 1);
      targetData.value.splice(end, 0, dragItem);
    }
    ctx.emit('targetDragEnd', [...targetData.value]);
  };

  onMounted(() => {
    const { data } = getTransferData();
    const sourceValues: TKey[] = [];
    const targetValues: TKey[] = [];
    data.forEach((item) => {
      if (props.sourceDefaultChecked.includes(item.value) && item.disabled === false) {
        sourceValues.push(item.value);
      }
      if (props.targetDefaultChecked.includes(item.value) && item.disabled === false) {
        targetValues.push(item.value);
      }
    });
    const sourceOption: IItem[] = [];
    const targetOption: IItem[] = [];
    data.forEach((item: IItem) => {
      if (props.modelValue.includes(item.value)) {
        targetOption.push(item);
      } else {
        sourceOption.push(item);
      }
    });
    sourceData.value = sourceOption;
    targetData.value = targetOption;
    sourceChecked.value = sourceValues;
    targetChecked.value = targetValues;
  });

  return {
    sourceTitle,
    targetTitle,
    sourceData,
    targetData,
    sourceDisabled,
    targetDisabled,
    sourceChecked,
    targetChecked,
    sourceDirection,
    targetDirection,
    updateSourceAllCheckedHandle,
    updateTargetAllCheckedHandle,
    updateSourceCheckedHandle,
    updateTargetCheckedHandle,
    toMoveTargetHandle,
    toMoveSourceHandle,
    updateSourceDataHandle,
    updateTargetDataHandle,
  };
};