<template>
  <view class="w-picker">
    <view class="w-picker-wrapper" @tap.passive="onShowPicker">
      <slot name="trigger" :label="displayValue" :value="selectedValues">
        <up-input
          readonly
          :border="border"
          v-model="displayValue"
          :inputAlign="align"
          :placeholder="placeholder"
          suffixIcon="arrow-right"
          :placeholder-style="`color: ${placeholderColor}`"
          :suffixIconStyle="{
            color: displayValue ? color : placeholderColor,
          }"
          :fontSize="size"
          :color="color"
        >
          <template #suffix v-if="displayValue">
            <view style="width: 12px" @click.stop="onClear">
              <view style="position: absolute; top: 0; bottom: 0; z-index: 100">
                <view class="clear" :style="iconStyle">
                  <u-icon name="close" size="8" color="#fff"></u-icon>
                </view>
              </view>
            </view>
          </template>
        </up-input>
      </slot>
      <div class="input-cover"></div>
    </view>
    <u-popup
      :show="show"
      @close="close"
      :closeOnClickOverlay="closeOnClickOverlay"
    >
      <view>
        <u-toolbar
          v-if="showToolbar"
          :cancelColor="cancelColor"
          :confirmColor="confirmColor"
          :cancelText="cancelText"
          :confirmText="confirmText"
          :title="title"
          @cancel="cancel"
          @confirm="confirm"
        ></u-toolbar>
        <view class="p--15">
          <scroll-view scroll-y style="max-height: 50vh">
            <up-checkbox-group
              v-model="tempSelectedValues"
              placement="column"
              iconPlacement="right"
              :activeColor="activeColor"
              @change="change"
              style="padding: 0 10px"
              :borderBottom="true"
            >
              <up-checkbox
                v-for="(item, index) in columns"
                :key="index"
                :name="state.isPlainArray ? item : item[valueName]"
                :label="state.isPlainArray ? item : item[keyName]"
                shape="circle"
                :style="{
                  fontWeight: isSelected(item) ? 'bold' : 500,
                }"
                :class="{ 'no-border': index === columns.length - 1 }"
              >
              </up-checkbox>
            </up-checkbox-group>
          </scroll-view>
        </view>
      </view>
    </u-popup>
  </view>
</template>

<script setup lang="ts">
import { ref, reactive, computed, watchEffect, watch } from "vue";

interface Item {
  [key: string]: any;
}

interface Props {
  modelValue: any;
  columns: Item[]; // 数据源 二维数组
  keyName?: string; //显示的属性名
  valueName?: string; //存储的属性名
  align?: "left" | "center" | "right" | undefined; //对齐方式 left\center\right
  border?: "none" | "bottom" | "surround" | undefined; // surround四周有边框,bottom底部有边框,none没有边框
  shape?: "circle" | "square" | undefined; //输入框形状 circle-圆形，square-方形 （ 默认 'square' ）
  title?: string; // 弹窗顶部标题
  size?: string; //文本大小
  color?: string; //选中的颜色
  placeholder?: string; //未选择时,提示文字
  placeholderColor?: string; //占位颜色
  closeOnClickOverlay?: boolean; //是否允许点击遮罩关闭选择器  ( 默认 false )
  showToolbar?: boolean;
  cancelText?: string;
  confirmText?: string;
  cancelColor?: string;
  confirmColor?: string;
  activeColor?: string; //选中颜色
}

const props = withDefaults(defineProps<Props>(), {
  border: "none",
  shape: "square",
  keyName: "name",
  valueName: "code",
  placeholder: "请选择",
  placeholderColor: "#c0c4cc",
  color: "#303133",
  size: "15",
  clearable: false,
  showToolbar: true,
  cancelText: "取消",
  confirmText: "确定",
  cancelColor: "#909193",
  confirmColor: "#3c9cff",
  closeOnClickOverlay: false,
});

const emit = defineEmits([
  "close",
  "cancel",
  "confirm",
  "change",
  "update:modelValue",
]);

const selectedValues = ref<any[]>([]); // 最终选中的值
const tempSelectedValues = ref<any[]>([]); // 临时选中的值
const show = ref(false);

const state = reactive({
  isPlainArray: computed(() => {
    const depth = getArrayDepth(props.columns);
    if (depth === 0) return false;
    const firstItem = props.columns[0];
    return !(
      firstItem &&
      typeof firstItem === "object" &&
      !Array.isArray(firstItem)
    );
  }),
  keyName: computed(() => props.keyName),
  valueName: computed(() => props.valueName),
});

const displayValue = computed(() => {
  if (state.isPlainArray) {
    return [...new Set(selectedValues.value)].join("/");
  } else {
    return props.columns
      .filter((item) => selectedValues.value?.includes(item[props.valueName]))
      ?.map((item) => item[props.keyName])
      .join("/");
  }
});

const iconStyle = computed(() => ({
  transform: props.border === "none" ? "translateY(5px)" : "translateY(11px)",
}));

const isSelected = (item: any) => {
  return state.isPlainArray
    ? tempSelectedValues.value?.includes(item)
    : tempSelectedValues.value?.includes(item[props.valueName]);
};

const onShowPicker = () => {
  show.value = true;
};

const change = (d: any) => {
  emit("change", d);
};

const confirm = () => {
  show.value = false;
  // 点击确定按钮后，同步临时选中值到 selectedValues
  selectedValues.value = [...tempSelectedValues.value];
  emit("update:modelValue", selectedValues.value);
  emit("confirm", selectedValues.value);
};

const cancel = () => {
  show.value = false;
  // 点击取消按钮后，恢复临时选中值为 selectedValues 的当前值
  tempSelectedValues.value = [...selectedValues.value];
  emit("cancel");
};

const close = () => {
  if (props.closeOnClickOverlay) {
    show.value = false;
    emit("close");
  }
};

const onClear = () => {
  selectedValues.value = [];
  tempSelectedValues.value = [];
  emit("update:modelValue", null);
};

function getArrayDepth(arr: any): number {
  if (!Array.isArray(arr)) return 0;
  return 1 + Math.max(0, ...arr.map(getArrayDepth));
}

watch(
  () => props.modelValue,
  (newValue) => {
    selectedValues.value = newValue ?? [];
    tempSelectedValues.value = newValue ?? []; // 同步临时选中值
  },
  { immediate: true }
);

watchEffect(() => {
  if (getArrayDepth(props.columns) === 0) return;
});
</script>

<style scoped lang="scss">
@mixin flex($direction: row) {
  display: flex;
  flex-direction: $direction;
}

.w-picker {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  .w-picker-wrapper {
    position: relative;
    width: 100%;
    cursor: pointer;
  }
  .clear {
    display: flex;
    align-items: center;
    justify-content: center;
    background: #c1c1c1;
    width: 15px;
    height: 15px;
    line-height: 15px;
    border-radius: 50%;
    .u-icon {
      margin-top: 1px;
    }
  }
}
.u-input {
  @include flex(row);
  align-items: center;
  flex: 1;

  &--radius,
  &--square {
    border-radius: 4px;
  }

  &--no-radius {
    border-radius: 0;
  }

  &--circle {
    border-radius: 100px;
  }
}
.input-cover {
  opacity: 0;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 1;
}
.no-border {
  border-bottom: none !important;
}
.u-border-bottom,
.up-border-bottom {
  border-color: #f2f2f2 !important;
}
</style>
