import { computed, type ComputedRef, type Ref } from 'vue'

/**
 * 三态选择面板的「已选数 + 已选项列表」派生
 *
 * - 三态优先级（与 dialog-picker-contract 对齐）：hide > locked > disabled
 *   - hide：永远剔除，不计数 / 不进已选列表
 *   - locked：默认勾选 + 计数 + 优先排在前面；即使被外部塞进 disabledIds 也胜出
 *   - disabled：仅过滤 selectedIds，不计数 / 不进已选列表
 * - 顺序：lockedIds 在前，selectedIds 紧随；按数组顺序即为「点击顺序」
 *
 * FriendPickerPanel / GroupMemberPickerPanel 共用，避免两侧 25 行同构 computed 各写一份；
 * Panel 内部的 isLocked / isDisabled / isSelected 等模板判定函数仍各自维护，本 composable 只承担派生量
 */
export function useSelectedItems<T>(
  selectedIds: () => readonly number[],
  lockedIds: () => readonly number[],
  disabledIds: () => readonly number[],
  hideIds: () => readonly number[],
  byId: ComputedRef<Map<number, T>> | Ref<Map<number, T>>
): {
  selectedCount: ComputedRef<number>
  selectedItems: ComputedRef<T[]>
} {
  const hideSet = computed(() => new Set(hideIds()))
  const disabledSet = computed(() => new Set(disabledIds()))

  const selectedCount = computed(() => {
    const merged = new Set<number>()
    for (const id of selectedIds()) {
      if (hideSet.value.has(id) || disabledSet.value.has(id)) {
        continue
      }
      merged.add(id)
    }
    // locked 仅被 hide 过滤；契约里 locked 胜过 disabled，确保锁定项始终计入
    for (const id of lockedIds()) {
      if (hideSet.value.has(id)) {
        continue
      }
      merged.add(id)
    }
    return merged.size
  })

  const selectedItems = computed(() => {
    const seen = new Set<number>()
    const result: T[] = []
    // locked 在前；仅被 hide 过滤
    for (const id of lockedIds()) {
      if (seen.has(id) || hideSet.value.has(id)) {
        continue
      }
      const item = byId.value.get(id)
      if (item) {
        seen.add(id)
        result.push(item)
      }
    }
    // selectedIds 紧随；额外过滤 disabled
    for (const id of selectedIds()) {
      if (seen.has(id) || disabledSet.value.has(id) || hideSet.value.has(id)) {
        continue
      }
      const item = byId.value.get(id)
      if (item) {
        seen.add(id)
        result.push(item)
      }
    }
    return result
  })

  return { selectedCount, selectedItems }
}
