<template>
  <div class="grouping-editor">
    <!-- Known limitation note (Open Question P3) -->
    <p class="grouping-editor__note">已知限制：不支持跨分组多选</p>

    <!-- Empty state (Open Question P2) -->
    <a-empty
      v-if="fields.length < 1"
      description="暂无可分组字段（请先创建字段）"
    />

    <template v-else>
      <a-select
        v-model:value="selectedFieldIds"
        mode="multiple"
        :max-tag-count="MAX_GROUP_BY_FIELDS"
        placeholder="选择分组字段（最多 3 个）"
        style="width: 100%"
        @change="onSelectionChange"
      >
        <a-select-option
          v-for="f in selectableFields"
          :key="f.id"
          :value="f.id"
          :disabled="
            !selectedFieldIds.includes(f.id) &&
            selectedFieldIds.length >= MAX_GROUP_BY_FIELDS
          "
        >
          {{ f.name }}
        </a-select-option>
      </a-select>

      <!-- Group-by levels with direction toggle + reorder -->
      <div
        v-for="(item, idx) in modelValue"
        :key="item.field_id"
        class="grouping-editor__level"
      >
        <span class="grouping-editor__level-index">{{ idx + 1 }}.</span>
        <span class="grouping-editor__level-name">{{ fieldName(item.field_id) }}</span>
        <a-radio-group
          :value="item.direction"
          size="small"
          @update:value="onDirectionChange(idx, $event)"
        >
          <a-radio-button value="asc">升序</a-radio-button>
          <a-radio-button value="desc">降序</a-radio-button>
        </a-radio-group>
        <a-button
          size="small"
          :disabled="idx === 0"
          :icon="h(ArrowUpOutlined)"
          @click="moveUp(idx)"
        />
        <a-button
          size="small"
          :disabled="idx === modelValue.length - 1"
          :icon="h(ArrowDownOutlined)"
          @click="moveDown(idx)"
        />
        <a-button
          size="small"
          danger
          :icon="h(DeleteOutlined)"
          @click="removeField(idx)"
        />
      </div>

      <p
        v-if="modelValue.length === MAX_GROUP_BY_FIELDS"
        class="grouping-editor__max-hint"
      >
        已达最大分组层数（{{ MAX_GROUP_BY_FIELDS }}）
      </p>
    </template>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, computed, h } from 'vue'
import {
  Select as ASelect,
  Empty as AEmpty,
  Button as AButton,
} from 'ant-design-vue'
import { ArrowUpOutlined, ArrowDownOutlined, DeleteOutlined } from '@ant-design/icons-vue'
import type { IBitableField } from '@/api/bitable'
import {
  MAX_GROUP_BY_FIELDS,
  type GroupByItem,
  type GroupDirection,
} from '@/helpers/groupingRulesUtils'

const props = defineProps<{
  modelValue: GroupByItem[]
  fields: IBitableField[]
}>()

const emit = defineEmits<{
  (e: 'update:modelValue', value: GroupByItem[]): void
}>()

// Local copy of the selected field ids — derived from modelValue but
// kept as a separate ref because a-select multiple mode wants string[].
const selectedFieldIds = ref<string[]>(
  props.modelValue.map((item) => item.field_id),
)

// Sync local selection when the parent's modelValue changes externally
// (e.g. after a successful PATCH reloads the view config).
watch(
  () => props.modelValue,
  (newVal) => {
    const newIds = newVal.map((item) => item.field_id)
    if (
      newIds.length !== selectedFieldIds.value.length ||
      !newIds.every((id, i) => id === selectedFieldIds.value[i])
    ) {
      selectedFieldIds.value = newIds
    }
  },
  { deep: true },
)

// All fields are selectable EXCEPT formula / lookup / attachment / image —
// these have opaque values that don't form meaningful groups. Number/text/
// date/select/multiselect all group by their scalar value.
const selectableFields = computed(() =>
  props.fields.filter(
    (f) =>
      f.field_type !== 'formula' &&
      f.field_type !== 'lookup' &&
      f.field_type !== 'attachment' &&
      f.field_type !== 'image',
  ),
)

function fieldName(fieldId: string): string {
  return props.fields.find((f) => f.id === fieldId)?.name ?? fieldId
}

function emitUpdate(items: GroupByItem[]): void {
  emit('update:modelValue', items)
}

function onSelectionChange(value: unknown): void {
  // a-select multiple emits SelectValue (string | number | Array | undefined);
  // narrow to string[] — mode="multiple" always yields an array in practice.
  const newIds = Array.isArray(value) ? value.map((v) => String(v)) : []
  // Preserve direction for existing items; default new items to 'asc'.
  const existing = new Map(props.modelValue.map((item) => [item.field_id, item]))
  const next: GroupByItem[] = newIds.map((id) => {
    const old = existing.get(id)
    return old ?? { field_id: id, direction: 'asc' as GroupDirection }
  })
  emitUpdate(next)
}

function onDirectionChange(idx: number, direction: GroupDirection): void {
  const next = props.modelValue.map((item, i) =>
    i === idx ? { ...item, direction } : item,
  )
  emitUpdate(next)
}

function moveUp(idx: number): void {
  if (idx === 0) return
  const next = [...props.modelValue]
  ;[next[idx - 1], next[idx]] = [next[idx], next[idx - 1]]
  emitUpdate(next)
}

function moveDown(idx: number): void {
  if (idx === props.modelValue.length - 1) return
  const next = [...props.modelValue]
  ;[next[idx], next[idx + 1]] = [next[idx + 1], next[idx]]
  emitUpdate(next)
}

function removeField(idx: number): void {
  const next = props.modelValue.filter((_, i) => i !== idx)
  // Also clear from local selection so the a-select re-enables the option.
  selectedFieldIds.value = next.map((item) => item.field_id)
  emitUpdate(next)
}
</script>

<style scoped>
.grouping-editor {
  display: flex;
  flex-direction: column;
  gap: var(--bitable-spacing-md);
}

.grouping-editor__note {
  font-size: var(--bitable-font-xs);
  color: var(--bitable-color-text-tertiary);
  margin: 0;
  padding: var(--bitable-spacing-xs) var(--bitable-spacing-sm);
  background: var(--bitable-color-bg-tertiary);
  border-radius: var(--bitable-radius-sm);
}

.grouping-editor__level {
  display: flex;
  align-items: center;
  gap: var(--bitable-spacing-sm);
  padding: var(--bitable-spacing-xs) 0;
  border-bottom: 1px solid var(--bitable-color-border-split);
}

.grouping-editor__level-index {
  font-weight: 600;
  color: var(--bitable-color-text-secondary);
  min-width: 24px;
}

.grouping-editor__level-name {
  flex: 1;
  font-size: var(--bitable-font-sm);
  color: var(--bitable-color-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.grouping-editor__max-hint {
  font-size: var(--bitable-font-xs);
  color: var(--bitable-color-text-tertiary);
  margin: 0;
}
</style>
