<script lang="ts" setup>

import { ref, watch } from 'vue';



import { Button, Input, InputNumber, Popover, Tag } from 'ant-design-vue';



type TagOption = { label: string; value: number | string };



const props = withDefaults(

  defineProps<{

    disabled?: boolean;

    displayFormatter?: (value: unknown) => string;

    label?: string;

    options?: TagOption[];

    placeholder?: string;

    type?: 'number' | 'tags' | 'text';

    value?: null | number | string;

  }>(),

  {

    disabled: false,

    label: '',

    options: () => [],

    placeholder: '请输入',

    type: 'text',

    value: '',

  },

);



const emit = defineEmits<{

  save: [value: number | string];

}>();



const open = ref(false);

const draftText = ref('');

const draftNumber = ref<null | number>(null);

const saving = ref(false);



watch(open, (visible) => {

  if (!visible) {

    return;

  }

  if (props.type === 'number') {

    const raw = props.value;

    draftNumber.value =

      raw !== null && raw !== undefined && raw !== '' ? Number(raw) : null;

    return;

  }

  draftText.value = String(props.value ?? '');

});



function displayText() {

  if (props.displayFormatter) {

    return props.displayFormatter(props.value);

  }

  if (props.value === null || props.value === undefined || props.value === '') {

    return '点击设置';

  }

  if (props.type === 'tags') {

    const matched = props.options.find(

      (item) => String(item.value) === String(props.value),

    );

    return matched?.label ?? String(props.value);

  }

  return String(props.value);

}



function isEmptyValue() {

  return props.value === null || props.value === undefined || props.value === '';

}



async function confirmSave() {

  saving.value = true;

  try {

    if (props.type === 'number') {

      if (draftNumber.value === null || draftNumber.value === undefined) {

        return;

      }

      emit('save', draftNumber.value);

    } else {

      const text = draftText.value.trim();

      if (!text) {

        return;

      }

      emit('save', text);

    }

    open.value = false;

  } finally {

    saving.value = false;

  }

}



function selectTag(value: number | string) {

  emit('save', value);

  open.value = false;

}

</script>



<template>

  <Popover v-model:open="open" trigger="click" placement="bottomLeft">

    <template #content>

      <div class="inline-editor-popover min-w-[220px]">

        <div v-if="label" class="mb-2 text-xs text-muted-foreground">{{ label }}</div>

        <template v-if="type === 'tags'">

          <div class="inline-editor-popover__tags">

            <Tag

              v-for="opt in options"

              :key="String(opt.value)"

              class="cursor-pointer transition-colors duration-200"

              :color="String(value) === String(opt.value) ? 'processing' : 'default'"

              @click="selectTag(opt.value)"

            >

              {{ opt.label }}

            </Tag>

          </div>

        </template>

        <template v-else-if="type === 'number'">

          <InputNumber

            v-model:value="draftNumber"

            class="w-full"

            :min="0"

            :placeholder="placeholder"

          />

          <div class="inline-editor-popover__actions">

            <Button size="small" @click="open = false">取消</Button>

            <Button

              size="small"

              type="primary"

              :loading="saving"

              @click="confirmSave"

            >

              保存

            </Button>

          </div>

        </template>

        <template v-else>

          <Input

            v-model:value="draftText"

            :placeholder="placeholder"

            @press-enter="confirmSave"

          />

          <div class="inline-editor-popover__actions">

            <Button size="small" @click="open = false">取消</Button>

            <Button

              size="small"

              type="primary"

              :loading="saving"

              @click="confirmSave"

            >

              保存

            </Button>

          </div>

        </template>

      </div>

    </template>

    <button

      type="button"

      class="inline-edit-trigger cursor-pointer border-b border-dashed border-transparent text-left transition-colors duration-200 hover:border-primary/50 hover:text-primary disabled:cursor-not-allowed disabled:opacity-50"

      :class="{

        'text-muted-foreground': isEmptyValue() && !displayFormatter,

      }"

      :disabled="disabled"

      @click.stop

    >

      {{ displayText() }}

    </button>

  </Popover>

</template>



<style scoped>

.inline-editor-popover__tags {

  display: flex;

  flex-wrap: wrap;

  gap: 8px;

  max-width: 280px;

}



.inline-editor-popover__actions {

  display: flex;

  justify-content: flex-end;

  gap: 8px;

  margin-top: 12px;

}

</style>

