<template>
  <div class="admin-wiki">
    <!-- Page Header -->
    <div class="page-header">
      <div class="header-row">
        <div>
          <h1>Wiki</h1>
          <p v-if="articles">
            {{ articles.length }} articles
            <template v-if="collections.length"> across {{ collections.length }} collections</template>
          </p>
        </div>
        <div class="header-actions">
          <button
            class="btn"
            :disabled="syncing"
            @click="syncFromOutline"
          >
            {{ syncing ? 'Syncing...' : 'Sync from Outline' }}
          </button>
        </div>
      </div>

      <!-- Sync Results -->
      <div v-if="syncResults" class="sync-results">
        <span v-if="syncResults.created" class="sync-stat sync-created">{{ syncResults.created }} created</span>
        <span v-if="syncResults.updated" class="sync-stat sync-updated">{{ syncResults.updated }} updated</span>
        <span v-if="syncResults.deleted" class="sync-stat sync-deleted">{{ syncResults.deleted }} removed</span>
        <span v-if="syncResults.errors" class="sync-stat sync-errors">{{ syncResults.errors }} errors</span>
        <span v-if="!syncResults.created && !syncResults.updated && !syncResults.deleted && !syncResults.errors" class="sync-stat">Already up to date</span>
      </div>
    </div>

    <!-- Filter Bar -->
    <div class="filter-bar">
      <div class="field" style="margin-bottom: 0; flex: 1">
        <input
          v-model="searchQuery"
          placeholder="Search articles by title..."
        />
      </div>
      <div class="field" style="margin-bottom: 0">
        <select v-model="collectionFilter" aria-label="Filter by collection">
          <option value="">All Collections</option>
          <option v-for="col in collections" :key="col" :value="col">{{ col }}</option>
        </select>
      </div>
      <div class="field" style="margin-bottom: 0">
        <select v-model="visibilityFilter" aria-label="Filter by visibility">
          <option value="">All</option>
          <option value="visible">Visible</option>
          <option value="hidden">Hidden</option>
        </select>
      </div>
      <div class="field" style="margin-bottom: 0">
        <select v-model="groupBy" aria-label="Group by">
          <option value="collection">Group by Collection</option>
          <option value="tag">Group by Tag</option>
          <option value="none">No Grouping</option>
        </select>
      </div>
    </div>

    <!-- Batch Action Bar -->
    <div v-if="selectedIds.length" class="batch-bar">
      <span class="batch-count">{{ selectedIds.length }} selected</span>
      <button
        v-if="collectionFilter && !allInCollectionSelected"
        class="link-btn"
        @click="selectAllInCollection"
      >
        Select all in "{{ collectionFilter }}"
      </button>
      <div class="batch-tag-picker">
        <select v-model="batchTagMode" aria-label="Batch tag mode" class="batch-select batch-mode-select">
          <option value="add">Add</option>
          <option value="remove">Remove</option>
        </select>
        <select v-model="batchTagSelected" :aria-label="batchTagMode === 'add' ? 'Tag to add' : 'Tag to remove'" class="batch-select">
          <option value="">Select tag...</option>
          <option v-for="tag in availableTags" :key="tag.slug" :value="tag.slug">{{ tag.label }}</option>
        </select>
        <button
          class="btn btn-primary"
          :disabled="!batchTagSelected || batchApplying"
          @click="applyBatchTag"
        >
          {{ batchApplying ? 'Applying...' : 'Apply' }}
        </button>
      </div>
      <div class="batch-visibility">
        <button
          class="btn btn-sm"
          :disabled="batchVisibilityApplying"
          @click="applyBatchVisibility(true)"
        >
          Hide
        </button>
        <button
          class="btn btn-sm"
          :disabled="batchVisibilityApplying"
          @click="applyBatchVisibility(false)"
        >
          Show
        </button>
      </div>
      <button class="link-btn" @click="selectedIds = []">Clear selection</button>
    </div>

    <!-- Loading / Error -->
    <div v-if="pending" class="loading-state">
      <div class="spinner" />
      <span>Loading articles...</span>
    </div>

    <div v-else-if="error" class="error-state">
      Error loading articles: {{ error }}
    </div>

    <!-- Article Table -->
    <div v-else class="table-wrap">
      <!-- Grouped view -->
      <template v-if="groupBy !== 'none' && visibleGroups.length">
        <details
          v-for="group in visibleGroups"
          :key="group.name"
          class="collection-group"
        >
          <summary class="collection-header">
            <span class="collection-name">{{ group.name }}</span>
            <span class="collection-count">{{ group.articles.length }}</span>
          </summary>
          <table>
            <thead>
              <tr>
                <th class="col-check">
                  <label class="custom-check" aria-label="Select all in group">
                    <input
                      type="checkbox"
                      :checked="allInGroupSelected(group.articles)"
                      :indeterminate="!allInGroupSelected(group.articles) && someInGroupSelected(group.articles)"
                      @change="toggleSelectGroup(group.articles)"
                    />
                    <span class="check-mark" />
                  </label>
                </th>
                <th class="col-title sortable" @click="toggleSort('title')">
                  Title <span v-if="sortKey === 'title'" class="sort-arrow">{{ sortDir === 'asc' ? '▲' : '▼' }}</span>
                </th>
                <th>Tags</th>
                <th class="col-vis sortable" @click="toggleSort('hidden')">
                  Vis <span v-if="sortKey === 'hidden'" class="sort-arrow">{{ sortDir === 'asc' ? '▲' : '▼' }}</span>
                </th>
                <th class="col-updated sortable" @click="toggleSort('outlineUpdatedAt')">
                  Updated <span v-if="sortKey === 'outlineUpdatedAt'" class="sort-arrow">{{ sortDir === 'asc' ? '▲' : '▼' }}</span>
                </th>
                <th class="col-actions-head">Actions</th>
              </tr>
            </thead>
            <tbody>
              <tr
                v-for="article in group.articles"
                :key="article._id"
                class="selectable-row"
                :class="{ 'row-selected': selectedIds.includes(article._id), 'row-hidden': article.hidden }"
                @click="toggleSelect(article._id)"
              >
                <td class="col-check" @click.stop>
                  <label class="custom-check" :aria-label="`Select ${article.title}`">
                    <input
                      type="checkbox"
                      :checked="selectedIds.includes(article._id)"
                      @change="toggleSelect(article._id)"
                    />
                    <span class="check-mark" />
                  </label>
                </td>
                <td class="col-title">
                  <a :href="article.url" target="_blank" rel="noopener" class="article-link" :class="{ 'article-hidden': article.hidden }">
                    {{ article.title }}
                  </a>
                </td>
                <td class="col-tags" @click.stop>
                  <div v-if="editingId !== article._id" class="tag-display">
                    <span v-for="tag in article.tags" :key="tag" class="tag-chip">{{ tagLabel(tag) }}</span>
                    <span v-if="!article.tags?.length" class="no-tags">no tags</span>
                  </div>
                  <div v-else class="tag-edit-inline">
                    <select
                      v-model="tagToAdd"
                      aria-label="Add tag"
                      class="tag-add-select"
                      @change="addTagToEditing"
                    >
                      <option value="">Add...</option>
                      <option
                        v-for="tag in availableTagsForEditing"
                        :key="tag.slug"
                        :value="tag.slug"
                      >{{ tag.label }}</option>
                    </select>
                    <div class="editing-tags">
                      <span
                        v-for="tag in editingTags"
                        :key="tag"
                        class="tag-chip tag-chip-editable"
                      >
                        {{ tagLabel(tag) }}
                        <button class="tag-remove" @click="removeTagFromEditing(tag)" aria-label="Remove tag">&times;</button>
                      </span>
                    </div>
                    <div class="tag-edit-actions">
                      <button class="link-btn" @click="cancelEditing">Cancel</button>
                      <button class="link-btn link-btn-save" :disabled="savingTags" @click="saveArticleTags">
                        {{ savingTags ? 'Saving...' : 'Save' }}
                      </button>
                    </div>
                  </div>
                </td>
                <td class="col-vis" @click.stop>
                  <button
                    class="vis-toggle"
                    :class="{ 'is-hidden': article.hidden }"
                    :title="article.hidden ? 'Hidden — click to show' : 'Visible — click to hide'"
                    @click="toggleArticleVisibility(article)"
                  >
                    {{ article.hidden ? '○' : '●' }}
                  </button>
                </td>
                <td class="col-updated">
                  {{ formatDate(article.outlineUpdatedAt) }}
                </td>
                <td class="col-actions" @click.stop>
                  <button
                    v-if="editingId !== article._id"
                    class="link-btn"
                    @click="startEditing(article)"
                  >
                    Edit tags
                  </button>
                </td>
              </tr>
            </tbody>
          </table>
        </details>
      </template>

      <!-- Flat view (no grouping) -->
      <template v-else-if="groupBy === 'none' && filtered.length">
        <table>
          <thead>
            <tr>
              <th class="col-check">
                <label class="custom-check" aria-label="Select all">
                  <input
                    type="checkbox"
                    :checked="allVisibleSelected"
                    :indeterminate="!allVisibleSelected && someVisibleSelected"
                    @change="toggleSelectAll"
                  />
                  <span class="check-mark" />
                </label>
              </th>
              <th class="col-title sortable" @click="toggleSort('title')">
                Title <span v-if="sortKey === 'title'" class="sort-arrow">{{ sortDir === 'asc' ? '▲' : '▼' }}</span>
              </th>
              <th class="sortable" @click="toggleSort('collection')">
                Collection <span v-if="sortKey === 'collection'" class="sort-arrow">{{ sortDir === 'asc' ? '▲' : '▼' }}</span>
              </th>
              <th>Tags</th>
              <th class="col-vis sortable" @click="toggleSort('hidden')">
                Vis <span v-if="sortKey === 'hidden'" class="sort-arrow">{{ sortDir === 'asc' ? '▲' : '▼' }}</span>
              </th>
              <th class="col-updated sortable" @click="toggleSort('outlineUpdatedAt')">
                Updated <span v-if="sortKey === 'outlineUpdatedAt'" class="sort-arrow">{{ sortDir === 'asc' ? '▲' : '▼' }}</span>
              </th>
              <th class="col-actions-head">Actions</th>
            </tr>
          </thead>
          <tbody>
            <tr
              v-for="article in filtered"
              :key="article._id"
              class="selectable-row"
              :class="{ 'row-selected': selectedIds.includes(article._id), 'row-hidden': article.hidden }"
              @click="toggleSelect(article._id)"
            >
              <td class="col-check" @click.stop>
                <label class="custom-check" :aria-label="`Select ${article.title}`">
                  <input
                    type="checkbox"
                    :checked="selectedIds.includes(article._id)"
                    @change="toggleSelect(article._id)"
                  />
                  <span class="check-mark" />
                </label>
              </td>
              <td class="col-title">
                <a :href="article.url" target="_blank" rel="noopener" class="article-link" :class="{ 'article-hidden': article.hidden }">
                  {{ article.title }}
                </a>
              </td>
              <td class="col-collection">{{ article.collection || '—' }}</td>
              <td class="col-tags" @click.stop>
                <div v-if="editingId !== article._id" class="tag-display">
                  <span v-for="tag in article.tags" :key="tag" class="tag-chip">{{ tagLabel(tag) }}</span>
                  <span v-if="!article.tags?.length" class="no-tags">no tags</span>
                </div>
                <div v-else class="tag-edit-inline">
                  <select
                    v-model="tagToAdd"
                    aria-label="Add tag"
                    class="tag-add-select"
                    @change="addTagToEditing"
                  >
                    <option value="">Add...</option>
                    <option
                      v-for="tag in availableTagsForEditing"
                      :key="tag.slug"
                      :value="tag.slug"
                    >{{ tag.label }}</option>
                  </select>
                  <div class="editing-tags">
                    <span
                      v-for="tag in editingTags"
                      :key="tag"
                      class="tag-chip tag-chip-editable"
                    >
                      {{ tagLabel(tag) }}
                      <button class="tag-remove" @click="removeTagFromEditing(tag)" aria-label="Remove tag">&times;</button>
                    </span>
                  </div>
                  <div class="tag-edit-actions">
                    <button class="link-btn" @click="cancelEditing">Cancel</button>
                    <button class="link-btn link-btn-save" :disabled="savingTags" @click="saveArticleTags">
                      {{ savingTags ? 'Saving...' : 'Save' }}
                    </button>
                  </div>
                </div>
              </td>
              <td class="col-vis" @click.stop>
                <button
                  class="vis-toggle"
                  :class="{ 'is-hidden': article.hidden }"
                  :title="article.hidden ? 'Hidden — click to show' : 'Visible — click to hide'"
                  @click="toggleArticleVisibility(article)"
                >
                  {{ article.hidden ? '○' : '●' }}
                </button>
              </td>
              <td class="col-updated">
                {{ formatDate(article.outlineUpdatedAt) }}
              </td>
              <td class="col-actions" @click.stop>
                <button
                  v-if="editingId !== article._id"
                  class="link-btn"
                  @click="startEditing(article)"
                >
                  Edit tags
                </button>
              </td>
            </tr>
          </tbody>
        </table>
      </template>

      <div v-else class="empty-state">
        No articles found matching your criteria
      </div>

      <!-- Hidden collections drawer -->
      <details v-if="groupBy !== 'none' && hiddenGroups.length" class="hidden-collections-drawer">
        <summary class="hidden-collections-header">
          <span>Hidden Collections</span>
          <span class="collection-count">{{ hiddenGroups.length }}</span>
        </summary>
        <details
          v-for="group in hiddenGroups"
          :key="group.name"
          class="collection-group hidden-collection"
        >
          <summary class="collection-header">
            <span class="collection-name">{{ group.name }}</span>
            <span class="collection-count">{{ group.articles.length }} articles</span>
            <button
              class="link-btn show-collection-btn"
              @click.stop="showCollection(group)"
            >
              Show Collection
            </button>
          </summary>
          <table>
            <thead>
              <tr>
                <th class="col-check">
                  <label class="custom-check" aria-label="Select all in group">
                    <input
                      type="checkbox"
                      :checked="allInGroupSelected(group.articles)"
                      :indeterminate="!allInGroupSelected(group.articles) && someInGroupSelected(group.articles)"
                      @change="toggleSelectGroup(group.articles)"
                    />
                    <span class="check-mark" />
                  </label>
                </th>
                <th class="col-title sortable" @click="toggleSort('title')">
                  Title <span v-if="sortKey === 'title'" class="sort-arrow">{{ sortDir === 'asc' ? '▲' : '▼' }}</span>
                </th>
                <th>Tags</th>
                <th class="col-vis sortable" @click="toggleSort('hidden')">
                  Vis <span v-if="sortKey === 'hidden'" class="sort-arrow">{{ sortDir === 'asc' ? '▲' : '▼' }}</span>
                </th>
                <th class="col-updated sortable" @click="toggleSort('outlineUpdatedAt')">
                  Updated <span v-if="sortKey === 'outlineUpdatedAt'" class="sort-arrow">{{ sortDir === 'asc' ? '▲' : '▼' }}</span>
                </th>
                <th class="col-actions-head">Actions</th>
              </tr>
            </thead>
            <tbody>
              <tr
                v-for="article in group.articles"
                :key="article._id"
                class="selectable-row"
                :class="{ 'row-selected': selectedIds.includes(article._id), 'row-hidden': article.hidden }"
                @click="toggleSelect(article._id)"
              >
                <td class="col-check" @click.stop>
                  <label class="custom-check" :aria-label="`Select ${article.title}`">
                    <input
                      type="checkbox"
                      :checked="selectedIds.includes(article._id)"
                      @change="toggleSelect(article._id)"
                    />
                    <span class="check-mark" />
                  </label>
                </td>
                <td class="col-title">
                  <a :href="article.url" target="_blank" rel="noopener" class="article-link article-hidden">
                    {{ article.title }}
                  </a>
                </td>
                <td class="col-tags" @click.stop>
                  <div v-if="editingId !== article._id" class="tag-display">
                    <span v-for="tag in article.tags" :key="tag" class="tag-chip">{{ tagLabel(tag) }}</span>
                    <span v-if="!article.tags?.length" class="no-tags">no tags</span>
                  </div>
                  <div v-else class="tag-edit-inline">
                    <select
                      v-model="tagToAdd"
                      aria-label="Add tag"
                      class="tag-add-select"
                      @change="addTagToEditing"
                    >
                      <option value="">Add...</option>
                      <option
                        v-for="tag in availableTagsForEditing"
                        :key="tag.slug"
                        :value="tag.slug"
                      >{{ tag.label }}</option>
                    </select>
                    <div class="editing-tags">
                      <span
                        v-for="tag in editingTags"
                        :key="tag"
                        class="tag-chip tag-chip-editable"
                      >
                        {{ tagLabel(tag) }}
                        <button class="tag-remove" @click="removeTagFromEditing(tag)" aria-label="Remove tag">&times;</button>
                      </span>
                    </div>
                    <div class="tag-edit-actions">
                      <button class="link-btn" @click="cancelEditing">Cancel</button>
                      <button class="link-btn link-btn-save" :disabled="savingTags" @click="saveArticleTags">
                        {{ savingTags ? 'Saving...' : 'Save' }}
                      </button>
                    </div>
                  </div>
                </td>
                <td class="col-vis" @click.stop>
                  <button
                    class="vis-toggle is-hidden"
                    title="Hidden — click to show"
                    @click="toggleArticleVisibility(article)"
                  >
                    ○
                  </button>
                </td>
                <td class="col-updated">
                  {{ formatDate(article.outlineUpdatedAt) }}
                </td>
                <td class="col-actions" @click.stop>
                  <button
                    v-if="editingId !== article._id"
                    class="link-btn"
                    @click="startEditing(article)"
                  >
                    Edit tags
                  </button>
                </td>
              </tr>
            </tbody>
          </table>
        </details>
      </details>
    </div>
  </div>
</template>

<script setup>
definePageMeta({
  layout: 'admin',
  middleware: 'admin',
})

const toast = useToast()

// ---- Data Fetching ----
const {
  data: articles,
  pending,
  error,
  refresh,
} = await useFetch('/api/admin/wiki')

const { data: tagsData } = await useFetch('/api/tags')

const availableTags = computed(() => tagsData.value?.tags || [])

const tagLabelMap = computed(() => {
  const map = {}
  for (const tag of availableTags.value) {
    map[tag.slug] = tag.label
  }
  return map
})

const tagLabel = (slug) => tagLabelMap.value[slug] || slug

// ---- Filters & Sort ----
const searchQuery = ref('')
const collectionFilter = ref('')
const visibilityFilter = ref('')
const groupBy = ref('collection')
const sortKey = ref('')
const sortDir = ref('asc')

const collections = computed(() => {
  if (!articles.value) return []
  const names = new Set()
  for (const a of articles.value) {
    if (a.collection) names.add(a.collection)
  }
  return [...names].sort()
})

const toggleSort = (key) => {
  if (sortKey.value === key) {
    sortDir.value = sortDir.value === 'asc' ? 'desc' : 'asc'
  } else {
    sortKey.value = key
    sortDir.value = 'asc'
  }
}

const filtered = computed(() => {
  if (!articles.value) return []

  const result = articles.value.filter((a) => {
    const q = searchQuery.value.toLowerCase()
    const matchesSearch = !q || a.title.toLowerCase().includes(q)
    const matchesCollection = !collectionFilter.value || a.collection === collectionFilter.value
    const matchesVisibility = !visibilityFilter.value
      || (visibilityFilter.value === 'hidden' && a.hidden)
      || (visibilityFilter.value === 'visible' && !a.hidden)
    return matchesSearch && matchesCollection && matchesVisibility
  })

  if (sortKey.value) {
    const dir = sortDir.value === 'asc' ? 1 : -1
    const key = sortKey.value
    result.sort((a, b) => {
      const aVal = (a[key] || '').toString().toLowerCase()
      const bVal = (b[key] || '').toString().toLowerCase()
      return aVal < bVal ? -dir : aVal > bVal ? dir : 0
    })
  }

  return result
})

const groupedFiltered = computed(() => {
  if (groupBy.value === 'none') return []

  const groups = new Map()

  if (groupBy.value === 'tag') {
    for (const article of filtered.value) {
      if (!article.tags?.length) {
        const key = 'Untagged'
        if (!groups.has(key)) groups.set(key, [])
        groups.get(key).push(article)
      } else {
        for (const tag of article.tags) {
          const key = tagLabel(tag)
          if (!groups.has(key)) groups.set(key, [])
          groups.get(key).push(article)
        }
      }
    }
  } else {
    for (const article of filtered.value) {
      const key = article.collection || 'Uncategorized'
      if (!groups.has(key)) groups.set(key, [])
      groups.get(key).push(article)
    }
  }

  return [...groups.entries()]
    .map(([name, articles]) => ({ name, articles }))
    .sort((a, b) => a.name.localeCompare(b.name))
})

const visibleGroups = computed(() => {
  if (visibilityFilter.value === 'hidden') return groupedFiltered.value
  return groupedFiltered.value.filter((group) =>
    group.articles.some((a) => !a.hidden),
  )
})

const hiddenGroups = computed(() => {
  if (visibilityFilter.value) return []
  return groupedFiltered.value.filter((group) =>
    group.articles.every((a) => a.hidden),
  )
})

const formatDate = (dateStr) => {
  if (!dateStr) return '—'
  const d = new Date(dateStr)
  return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
}

// ---- Selection ----
const selectedIds = ref([])

const allVisibleSelected = computed(() => {
  if (!filtered.value.length) return false
  return filtered.value.every((a) => selectedIds.value.includes(a._id))
})

const someVisibleSelected = computed(() => {
  return filtered.value.some((a) => selectedIds.value.includes(a._id))
})

const allInCollectionSelected = computed(() => {
  if (!collectionFilter.value || !articles.value) return false
  const inCollection = articles.value.filter((a) => a.collection === collectionFilter.value)
  return inCollection.every((a) => selectedIds.value.includes(a._id))
})

const toggleSelectAll = () => {
  if (allVisibleSelected.value) {
    const visibleIds = new Set(filtered.value.map((a) => a._id))
    selectedIds.value = selectedIds.value.filter((id) => !visibleIds.has(id))
  } else {
    const currentSet = new Set(selectedIds.value)
    for (const a of filtered.value) {
      currentSet.add(a._id)
    }
    selectedIds.value = [...currentSet]
  }
}

const toggleSelect = (id) => {
  const idx = selectedIds.value.indexOf(id)
  if (idx >= 0) {
    selectedIds.value.splice(idx, 1)
  } else {
    selectedIds.value.push(id)
  }
}

const allInGroupSelected = (groupArticles) => {
  if (!groupArticles.length) return false
  return groupArticles.every((a) => selectedIds.value.includes(a._id))
}

const someInGroupSelected = (groupArticles) => {
  return groupArticles.some((a) => selectedIds.value.includes(a._id))
}

const toggleSelectGroup = (groupArticles) => {
  if (allInGroupSelected(groupArticles)) {
    const groupIds = new Set(groupArticles.map((a) => a._id))
    selectedIds.value = selectedIds.value.filter((id) => !groupIds.has(id))
  } else {
    const currentSet = new Set(selectedIds.value)
    for (const a of groupArticles) {
      currentSet.add(a._id)
    }
    selectedIds.value = [...currentSet]
  }
}

const selectAllInCollection = () => {
  if (!collectionFilter.value || !articles.value) return
  const currentSet = new Set(selectedIds.value)
  for (const a of articles.value) {
    if (a.collection === collectionFilter.value) {
      currentSet.add(a._id)
    }
  }
  selectedIds.value = [...currentSet]
}

// ---- Sync ----
const syncing = ref(false)
const syncResults = ref(null)

const syncFromOutline = async () => {
  syncing.value = true
  syncResults.value = null
  try {
    const result = await $fetch('/api/admin/wiki/sync', { method: 'POST' })
    syncResults.value = result
    await refresh()
    toast.add({
      title: 'Sync complete',
      description: `${result.created} created, ${result.updated} updated, ${result.deleted} removed`,
      color: result.errors ? 'orange' : 'green',
    })
  } catch (err) {
    toast.add({
      title: 'Sync failed',
      description: err.data?.statusMessage || err.message,
      color: 'red',
    })
  } finally {
    syncing.value = false
  }
}

// ---- Per-Article Tag Editing ----
const editingId = ref(null)
const editingTags = ref([])
const tagToAdd = ref('')
const savingTags = ref(false)

const availableTagsForEditing = computed(() => {
  return availableTags.value.filter((t) => !editingTags.value.includes(t.slug))
})

const startEditing = (article) => {
  editingId.value = article._id
  editingTags.value = [...(article.tags || [])]
  tagToAdd.value = ''
}

const cancelEditing = () => {
  editingId.value = null
  editingTags.value = []
  tagToAdd.value = ''
}

const addTagToEditing = () => {
  if (tagToAdd.value && !editingTags.value.includes(tagToAdd.value)) {
    editingTags.value.push(tagToAdd.value)
  }
  tagToAdd.value = ''
}

const removeTagFromEditing = (tag) => {
  editingTags.value = editingTags.value.filter((t) => t !== tag)
}

const saveArticleTags = async () => {
  savingTags.value = true
  try {
    await $fetch(`/api/admin/wiki/${editingId.value}`, {
      method: 'PATCH',
      body: { tags: editingTags.value },
    })
    await refresh()
    cancelEditing()
    toast.add({ title: 'Tags updated', color: 'green' })
  } catch (err) {
    toast.add({
      title: 'Failed to update tags',
      description: err.data?.statusMessage || err.message,
      color: 'red',
    })
  } finally {
    savingTags.value = false
  }
}

// ---- Batch Tagging ----
const batchTagMode = ref('add')
const batchTagSelected = ref('')
const batchApplying = ref(false)

const applyBatchTag = async () => {
  if (!batchTagSelected.value || !selectedIds.value.length) return
  batchApplying.value = true
  try {
    const body = { articleIds: selectedIds.value }
    if (batchTagMode.value === 'add') {
      body.addTags = [batchTagSelected.value]
    } else {
      body.removeTags = [batchTagSelected.value]
    }
    const result = await $fetch('/api/admin/wiki/batch-tag', {
      method: 'POST',
      body,
    })
    await refresh()
    const action = batchTagMode.value === 'add' ? 'added to' : 'removed from'
    toast.add({
      title: `Tag ${action} ${result.modified} articles`,
      color: 'green',
    })
    batchTagSelected.value = ''
    selectedIds.value = []
  } catch (err) {
    toast.add({
      title: 'Batch tag failed',
      description: err.data?.statusMessage || err.message,
      color: 'red',
    })
  } finally {
    batchApplying.value = false
  }
}

// ---- Visibility Toggle ----
const toggleArticleVisibility = async (article) => {
  try {
    await $fetch(`/api/admin/wiki/${article._id}`, {
      method: 'PATCH',
      body: { hidden: !article.hidden },
    })
    await refresh()
  } catch (err) {
    toast.add({
      title: 'Failed to update visibility',
      description: err.data?.statusMessage || err.message,
      color: 'red',
    })
  }
}

// ---- Show Entire Collection ----
const showCollection = async (group) => {
  const ids = group.articles.map((a) => a._id)
  try {
    await $fetch('/api/admin/wiki/batch-visibility', {
      method: 'POST',
      body: { articleIds: ids, hidden: false },
    })
    await refresh()
    toast.add({
      title: `${group.name} is now visible`,
      color: 'green',
    })
  } catch (err) {
    toast.add({
      title: 'Failed to show collection',
      description: err.data?.statusMessage || err.message,
      color: 'red',
    })
  }
}

// ---- Batch Visibility ----
const batchVisibilityApplying = ref(false)

const applyBatchVisibility = async (hidden) => {
  if (!selectedIds.value.length) return
  batchVisibilityApplying.value = true
  try {
    const result = await $fetch('/api/admin/wiki/batch-visibility', {
      method: 'POST',
      body: { articleIds: selectedIds.value, hidden },
    })
    await refresh()
    toast.add({
      title: `${result.modified} articles ${hidden ? 'hidden' : 'shown'}`,
      color: 'green',
    })
    selectedIds.value = []
  } catch (err) {
    toast.add({
      title: 'Batch visibility failed',
      description: err.data?.statusMessage || err.message,
      color: 'red',
    })
  } finally {
    batchVisibilityApplying.value = false
  }
}
</script>

<style scoped>
.admin-wiki {}

/* ---- PAGE HEADER ---- */
.page-header {
  padding: 28px 28px 20px;
  border-bottom: 1px dashed var(--border);
}

.header-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  flex-wrap: wrap;
}

.page-header h1 {
  font-family: 'Brygada 1918', serif;
  font-size: 24px;
  font-weight: 500;
  color: var(--text-bright);
  line-height: 1.2;
  margin-bottom: 4px;
}

.page-header p {
  font-size: 12px;
  color: var(--text-dim);
}

.header-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}

/* ---- SYNC RESULTS ---- */
.sync-results {
  display: flex;
  gap: 12px;
  margin-top: 12px;
  flex-wrap: wrap;
}

.sync-stat {
  font-size: 11px;
  padding: 2px 8px;
  border: 1px dashed var(--border);
  color: var(--text-dim);
}

.sync-created {
  color: var(--green, #4a7);
  border-color: var(--green, #4a7);
}

.sync-updated {
  color: var(--candle);
  border-color: var(--candle);
}

.sync-deleted {
  color: var(--text-faint);
}

.sync-errors {
  color: var(--ember);
  border-color: var(--ember);
}

/* ---- FILTER BAR ---- */
.filter-bar {
  display: flex;
  gap: 12px;
  padding: 16px 28px;
  border-bottom: 1px dashed var(--border);
}

/* ---- BATCH ACTION BAR ---- */
.batch-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 28px;
  border-bottom: 1px dashed var(--border);
  background: var(--surface);
  flex-wrap: wrap;
}

.batch-count {
  font-size: 12px;
  color: var(--text-bright);
  font-weight: 500;
}

.batch-tag-picker {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-left: auto;
}

.batch-select {
  font-family: 'Commit Mono', monospace;
  font-size: 12px;
  padding: 4px 8px;
  border: 1px solid var(--border);
  background: var(--input-bg);
  color: var(--text);
}

.batch-select:focus {
  border-color: var(--candle);
  outline: none;
}

.batch-mode-select {
  width: auto;
  min-width: 80px;
}

/* ---- COLLECTION GROUPS ---- */
.collection-group {
  border-bottom: 1px dashed var(--border);
}

.collection-group:last-child {
  border-bottom: none;
}

.collection-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 28px;
  cursor: pointer;
  list-style: none;
  user-select: none;
  border-bottom: 1px dashed var(--border);
  transition: background 0.1s;
}

.collection-header:hover {
  background: var(--surface);
}

.collection-header::-webkit-details-marker {
  display: none;
}

.collection-header::before {
  content: "▸";
  font-size: 11px;
  color: var(--text-faint);
  transition: transform 0.15s;
}

.collection-group[open] > .collection-header::before {
  content: "▾";
}

.collection-name {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-bright);
}

.collection-count {
  font-size: 11px;
  color: var(--text-faint);
}

.col-updated {
  font-size: 11px;
  color: var(--text-dim);
  white-space: nowrap;
  width: 100px;
}

/* ---- HIDDEN COLLECTIONS DRAWER ---- */
.hidden-collections-drawer {
  margin-top: 24px;
  border-top: 1px dashed var(--border);
}

.hidden-collections-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 28px;
  cursor: pointer;
  list-style: none;
  user-select: none;
  font-size: 12px;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.hidden-collections-header::-webkit-details-marker {
  display: none;
}

.hidden-collections-header::before {
  content: "▸";
  font-size: 11px;
  color: var(--text-faint);
}

.hidden-collections-drawer[open] > .hidden-collections-header::before {
  content: "▾";
}

.hidden-collection .collection-header {
  padding-left: 44px;
}

.show-collection-btn {
  margin-left: auto;
}

/* ---- TABLE ---- */
.table-wrap {
  padding: 0 0 24px;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

thead th {
  text-align: left;
  padding: 12px 10px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-faint);
  border-bottom: 1px dashed var(--border);
  font-weight: normal;
}

thead th.sortable {
  cursor: pointer;
  user-select: none;
}

thead th.sortable:hover {
  color: var(--text-dim);
}

.sort-arrow {
  font-size: 10px;
  color: var(--candle);
}

tbody tr {
  border-bottom: 1px dashed var(--border);
  transition: background 0.1s;
}

tbody tr:hover {
  background: var(--surface);
}

tbody td {
  padding: 10px;
  color: var(--text);
  vertical-align: middle;
}

.col-check {
  width: 40px;
  padding-left: 12px;
  padding-right: 4px;
}

.selectable-row {
  cursor: pointer;
}

.row-selected {
  background: var(--surface);
}

/* ---- CUSTOM CHECKBOX ---- */
.custom-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  position: relative;
  width: 16px;
  height: 16px;
}

.custom-check input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.check-mark {
  width: 14px;
  height: 14px;
  border: 1px solid var(--border);
  background: var(--input-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.15s, background 0.15s;
}

.custom-check:hover .check-mark {
  border-color: var(--candle);
}

.custom-check input:checked + .check-mark {
  background: var(--candle);
  border-color: var(--candle);
}

.custom-check input:checked + .check-mark::after {
  content: '';
  width: 4px;
  height: 8px;
  border: solid var(--bg);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg) translateY(-1px);
}

.custom-check input:indeterminate + .check-mark {
  background: var(--candle);
  border-color: var(--candle);
}

.custom-check input:indeterminate + .check-mark::after {
  content: '';
  width: 8px;
  height: 0;
  border-bottom: 1.5px solid var(--bg);
}

/* ---- VISIBILITY ---- */
.col-vis {
  width: 50px;
  text-align: center;
}

.vis-toggle {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 14px;
  color: var(--candle);
  padding: 2px 6px;
  line-height: 1;
}

.vis-toggle.is-hidden {
  color: var(--text-faint);
}

.vis-toggle:hover {
  opacity: 0.7;
}

.row-hidden {
  opacity: 0.5;
}

.article-hidden {
  text-decoration: line-through;
  color: var(--text-faint);
}

.batch-visibility {
  display: flex;
  gap: 6px;
}

.btn-sm {
  font-size: 11px;
  padding: 3px 10px;
}

/* ---- COLUMNS ---- */
.col-collection {
  font-size: 11px;
  color: var(--text-dim);
  white-space: nowrap;
}

.col-title {
  min-width: 200px;
}

.article-link {
  color: var(--text-bright);
  font-size: 13px;
  text-decoration: none;
}

.article-link:hover {
  color: var(--candle);
  text-decoration: underline;
}

/* ---- TAGS ---- */
.col-tags {
  min-width: 180px;
}

.tag-display {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.tag-chip {
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 6px;
  border: 1px dashed var(--border);
  color: var(--text-dim);
}

.tag-chip-editable {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.tag-remove {
  background: none;
  border: none;
  color: var(--text-faint);
  font-size: 14px;
  cursor: pointer;
  padding: 0 2px;
  line-height: 1;
}

.tag-remove:hover {
  color: var(--ember);
}

.no-tags {
  font-size: 11px;
  color: var(--text-faint);
  font-style: italic;
}

/* ---- INLINE TAG EDITING ---- */
.tag-edit-inline {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.tag-add-select {
  font-family: 'Commit Mono', monospace;
  font-size: 11px;
  padding: 3px 6px;
  border: 1px solid var(--border);
  background: var(--input-bg);
  color: var(--text);
  max-width: 160px;
}

.tag-add-select:focus {
  border-color: var(--candle);
  outline: none;
}

.editing-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.tag-edit-actions {
  display: flex;
  gap: 8px;
}

/* ---- ACTIONS ---- */
.col-actions-head {
  text-align: right;
}

.col-actions {
  text-align: right;
  white-space: nowrap;
}

.link-btn {
  background: none;
  border: none;
  color: var(--candle);
  cursor: pointer;
  font-family: 'Commit Mono', monospace;
  font-size: 11px;
  padding: 2px 6px;
  text-decoration: none;
}

.link-btn:hover {
  text-decoration: underline;
}

.link-btn:disabled {
  color: var(--text-faint);
  cursor: default;
  text-decoration: none;
}

.link-btn-save {
  font-weight: 500;
}

/* ---- STATES ---- */
.loading-state {
  text-align: center;
  padding: 48px 24px;
  color: var(--text-faint);
  font-size: 12px;
}

.error-state {
  text-align: center;
  padding: 48px 24px;
  color: var(--ember);
  font-size: 12px;
}

.empty-state {
  text-align: center;
  padding: 48px 24px;
  color: var(--text-faint);
  font-size: 12px;
}

.spinner {
  width: 24px;
  height: 24px;
  border: 2px dashed var(--candle);
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin: 0 auto 12px;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* ---- RESPONSIVE ---- */
@media (max-width: 768px) {
  .page-header {
    padding: 24px 20px 16px;
  }

  .header-row {
    flex-direction: column;
  }

  .filter-bar {
    flex-direction: column;
    padding: 12px 20px;
  }

  .batch-bar {
    flex-direction: column;
    align-items: flex-start;
    padding: 12px 20px;
  }

  .batch-tag-picker {
    margin-left: 0;
  }

  .table-wrap {
    padding: 0 12px 20px;
    overflow-x: auto;
  }

  table {
    min-width: 600px;
  }
}
</style>
