<template>
  <v-card class="fc-tqb">
    <v-card-title class="fc-tqb__head">
      <v-icon icon="mdi-filter-cog-outline" size="small" class="mr-2" />
      Advanced tag filter
      <v-spacer />
      <v-btn
        icon="mdi-close" variant="text" size="small"
        aria-label="Close advanced tag filter" @click="$emit('close')"
      />
    </v-card-title>

    <v-card-text>
      <p class="text-body-2 fc-tqb__hint">
        An image must match <strong>every</strong> group below, and a group
        matches when the image carries <strong>any</strong> tag in it
        (AND of ORs). Excluded tags are never shown.
      </p>

      <!-- AND-of-OR groups -->
      <div class="fc-tqb__section">
        <div class="fc-tqb__section-title">Must match all of</div>

        <p v-if="!groups.length" class="fc-tqb__empty">
          No groups yet — add a tag below to start.
        </p>

        <template v-for="(g, gi) in groups" :key="gi">
          <div v-if="gi > 0" class="fc-tqb__and">AND</div>
          <div class="fc-tqb__group">
            <div class="fc-tqb__group-chips">
              <template v-for="(id, ci) in g" :key="id">
                <span v-if="ci > 0" class="fc-tqb__or">or</span>
                <v-chip
                  size="small" closable variant="tonal"
                  :color="kindColor(id)"
                  @click:close="removeFromGroup(gi, id)"
                >{{ label(id) }}</v-chip>
              </template>
              <span v-if="!g.length" class="fc-tqb__empty">empty</span>
            </div>
            <div class="fc-tqb__group-actions">
              <TagPicker
                placeholder="or…" class="fc-tqb__picker"
                @pick="(t) => addToGroup(gi, t)"
              />
              <v-btn
                icon="mdi-delete-outline" variant="text" size="small"
                aria-label="Remove this group" @click="removeGroup(gi)"
              />
            </div>
          </div>
        </template>

        <div class="fc-tqb__add">
          <TagPicker
            placeholder="Add a tag (new group)…" class="fc-tqb__picker"
            @pick="addNewGroup"
          />
        </div>
      </div>

      <v-divider class="my-4" />

      <!-- exclude -->
      <div class="fc-tqb__section">
        <div class="fc-tqb__section-title">Exclude (must NOT have)</div>
        <div class="fc-tqb__group-chips">
          <v-chip
            v-for="id in excludeIds" :key="id"
            size="small" closable color="error" variant="tonal"
            @click:close="removeExclude(id)"
          >
            <v-icon start size="x-small">mdi-minus</v-icon>{{ label(id) }}
          </v-chip>
          <span v-if="!excludeIds.length" class="fc-tqb__empty">none</span>
        </div>
        <div class="fc-tqb__add">
          <TagPicker
            placeholder="Exclude a tag…" class="fc-tqb__picker"
            @pick="addExclude"
          />
        </div>
      </div>
    </v-card-text>

    <v-card-actions class="fc-tqb__actions">
      <v-btn
        variant="text" size="small" :disabled="!isDirty && isEmpty"
        @click="clearAll"
      >Clear</v-btn>
      <v-spacer />
      <v-btn variant="text" @click="$emit('close')">Cancel</v-btn>
      <v-btn color="accent" variant="flat" rounded="pill" @click="apply">
        Apply filter
      </v-btn>
    </v-card-actions>
  </v-card>
</template>

<script setup>
import { ref, computed } from 'vue'
import { useTagStore } from '../../stores/tags.js'
import TagPicker from '../common/TagPicker.vue'

// One editor for the whole structured tag model. It works purely on "AND-of-OR
// groups + exclude": singleton includes (tag_ids) and OR-groups (tag_or) are
// unified into one `groups` list here, then split back apart on Apply so the
// URL stays compact (singletons serialize to tag_id, multi-tag groups to
// tag_or). Writes the SAME model the light chips edit — two editors, one model.
const props = defineProps({
  include: { type: Array, default: () => [] },     // tag_ids
  orGroups: { type: Array, default: () => [] },    // tag_or
  exclude: { type: Array, default: () => [] },     // tag_exclude
  labels: { type: Object, default: () => ({}) },   // id -> name (best effort)
})
const emit = defineEmits(['apply', 'close'])

const tagStore = useTagStore()

// Seed local draft from props (the dialog is recreated on each open, so a
// setup-time seed is the current filter every time).
const groups = ref([
  ...props.include.map((id) => [id]),
  ...props.orGroups.map((g) => [...g]),
])
const excludeIds = ref([...props.exclude])

// Names/kinds learned as tags are picked, layered over the labels passed in.
const nameMap = ref({ ...props.labels })
const kindMap = ref({})

function label (id) { return nameMap.value[id] || `#${id}` }
function kindColor (id) { return tagStore.colorFor(kindMap.value[id] || 'general') }

function _note (tag) {
  nameMap.value = { ...nameMap.value, [tag.id]: tag.name }
  kindMap.value = { ...kindMap.value, [tag.id]: tag.kind }
}
function _dropFromGroups (id) {
  groups.value = groups.value
    .map((g) => g.filter((t) => t !== id))
    .filter((g) => g.length)
}

function addToGroup (gi, tag) {
  _note(tag)
  excludeIds.value = excludeIds.value.filter((t) => t !== tag.id)  // can't be both
  if (!groups.value[gi].includes(tag.id)) groups.value[gi].push(tag.id)
}
function addNewGroup (tag) {
  _note(tag)
  excludeIds.value = excludeIds.value.filter((t) => t !== tag.id)
  groups.value.push([tag.id])
}
function removeFromGroup (gi, id) {
  groups.value[gi] = groups.value[gi].filter((t) => t !== id)
  if (!groups.value[gi].length) groups.value.splice(gi, 1)
}
function removeGroup (gi) { groups.value.splice(gi, 1) }

function addExclude (tag) {
  _note(tag)
  _dropFromGroups(tag.id)  // a tag can't be both required and excluded
  if (!excludeIds.value.includes(tag.id)) excludeIds.value.push(tag.id)
}
function removeExclude (id) {
  excludeIds.value = excludeIds.value.filter((t) => t !== id)
}

function clearAll () { groups.value = []; excludeIds.value = [] }

const isEmpty = computed(() => !groups.value.length && !excludeIds.value.length)
const isDirty = computed(() =>
  JSON.stringify(groups.value) !== JSON.stringify(props.orGroups.length || props.include.length
    ? [...props.include.map((id) => [id]), ...props.orGroups]
    : []) ||
  JSON.stringify(excludeIds.value) !== JSON.stringify(props.exclude),
)

function apply () {
  const clean = groups.value.filter((g) => g.length)
  emit('apply', {
    tag_ids: clean.filter((g) => g.length === 1).map((g) => g[0]),
    tag_or: clean.filter((g) => g.length > 1),
    tag_exclude: [...excludeIds.value],
    labels: nameMap.value,  // so freshly-picked chips show their name on return
  })
}
</script>

<style scoped>
.fc-tqb__head { display: flex; align-items: center; }
.fc-tqb__hint {
  color: rgb(var(--v-theme-on-surface-variant));
  margin-bottom: 16px;
}
.fc-tqb__section { margin-bottom: 4px; }
.fc-tqb__section-title {
  font-size: 12px; font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgb(var(--v-theme-on-surface-variant));
  margin-bottom: 8px;
}
.fc-tqb__and {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
  color: rgb(var(--v-theme-accent));
  margin: 6px 0 6px 2px;
}
.fc-tqb__group {
  display: flex; align-items: center; gap: 12px;
  flex-wrap: wrap;
  padding: 8px 10px;
  border: 1px solid rgba(var(--v-theme-on-surface), 0.12);
  border-radius: 10px;
  background: rgba(var(--v-theme-on-surface), 0.03);
}
.fc-tqb__group-chips {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  flex: 1 1 220px; min-width: 0;
}
.fc-tqb__or {
  font-size: 11px; font-style: italic;
  color: rgb(var(--v-theme-on-surface-variant));
}
.fc-tqb__group-actions {
  display: flex; align-items: center; gap: 4px;
}
.fc-tqb__picker { min-width: 180px; max-width: 240px; }
.fc-tqb__add { margin-top: 10px; max-width: 280px; }
.fc-tqb__empty {
  font-size: 12px; font-style: italic;
  color: rgb(var(--v-theme-on-surface-variant));
}
.fc-tqb__actions { padding: 8px 16px 16px; }
</style>
