<script setup>
/**
 * TagEditor — Universal inline tag editor with autocomplete.
 *
 * Features:
 *  - Autocomplete from allTags (label + color dot + category)
 *  - Click chip → inline rename (Enter to save, Esc to cancel)
 *  - Right-click chip → mini popover: rename, color picker, delete
 *  - Optional `level` badge per tag (for skill proficiency on resources)
 *  - Create new tags on-the-fly with color picker
 *  - Reusable everywhere: jobs, techs, sidebar filter
 */
import { ref, computed, nextTick, watch, onMounted } from 'vue'
import { useQuasar } from 'quasar'
import draggable from 'vuedraggable' // réordonnancement des chips (priorité de compétence) — glisser-déposer, marche au doigt

const $q = useQuasar()
const isDark = computed(() => $q.dark.isActive)

const props = defineProps({
  modelValue:  { type: Array, default: () => [] },        // [{ tag, level? }] or ['label', ...]
  allTags:     { type: Array, default: () => [] },         // [{ name, label, color, category }]
  getColor:    { type: Function, default: () => '#6b7280' },
  placeholder: { type: String, default: 'Ajouter un tag…' },
  canCreate:   { type: Boolean, default: true },
  canEdit:     { type: Boolean, default: true },           // allow inline rename/color/delete
  showLevel:   { type: Boolean, default: false },          // show skill level per tag
  levelLabel:  { type: String, default: 'Compétence' },    // context label for level
  levelHint:   { type: String, default: '1 = base · 5 = expert' },
  showRequired:{ type: Boolean, default: false },          // show required pin per tag (jobs)
  compact:     { type: Boolean, default: false },          // smaller chips
  autofocus:   { type: Boolean, default: false },          // focus l'input au montage (ouvre la liste direct)
  sortable:    { type: Boolean, default: false },          // glisser-déposer pour réordonner les chips (ORDRE = priorité) ; 1er = principal
})
const emit = defineEmits(['update:modelValue', 'create', 'update-tag', 'rename-tag', 'delete-tag'])

// Normalise modelValue: accept both string[] and {tag, level, required}[]
function _labels () {
  return props.modelValue.map(v => typeof v === 'string' ? v : v.tag)
}
function _lbl (v) { return typeof v === 'string' ? v : (v && v.tag) } // libellé d'un item (string ou {tag})
function _itemKey (v) { return _lbl(v) }
function onReorder (v) { emit('update:modelValue', v) } // glisser-déposer → nouvel ordre = nouvelle priorité (émis tel quel, préserve level/required)
function _getLevel (label) {
  const item = props.modelValue.find(v => typeof v !== 'string' && v.tag === label)
  return item?.level ?? 0
}
function _isRequired (label) {
  const item = props.modelValue.find(v => typeof v !== 'string' && v.tag === label)
  return !!(item?.required)
}

// ─── Search / autocomplete ──────────────────────────────────────────────────
const query = ref('')
const focused = ref(false)
const inputEl = ref(null)

const filtered = computed(() => {
  const labels = _labels()
  const q = query.value.trim().toLowerCase()
  const pool = props.allTags.filter(t => !labels.includes(t.label) && !labels.includes(t.name))
  if (!q) return pool.slice(0, 14)
  return pool.filter(t => t.label.toLowerCase().includes(q)).slice(0, 14)
})

const showCreate = computed(() => {
  if (!props.canCreate) return false
  const q = query.value.trim()
  if (!q || q.length < 2) return false
  return !props.allTags.some(t => t.label.toLowerCase() === q.toLowerCase())
})

// ─── Add / remove ───────────────────────────────────────────────────────────
function addTag (label) {
  if (!label || _labels().includes(label)) return
  const useObj = props.showLevel || props.showRequired
  const out = useObj
    ? [...props.modelValue, { tag: label, level: 1, required: 0 }]
    : [...props.modelValue, label]
  emit('update:modelValue', out)
  query.value = ''
}

function removeTag (label) {
  const out = props.modelValue.filter(v => (typeof v === 'string' ? v : v.tag) !== label)
  emit('update:modelValue', out)
}

// ─── Level change ───────────────────────────────────────────────────────────
function setLevel (label, level) {
  const out = props.modelValue.map(v => {
    if (typeof v !== 'string' && v.tag === label) return { ...v, level }
    return v
  })
  emit('update:modelValue', out)
}

// ─── Required toggle (jobs) ─────────────────────────────────────────────────
function toggleRequired (label) {
  const out = props.modelValue.map(v => {
    if (typeof v !== 'string' && v.tag === label) return { ...v, required: v.required ? 0 : 1 }
    return v
  })
  emit('update:modelValue', out)
}

// ─── Create new tag ─────────────────────────────────────────────────────────
const newColor = ref('#6b7280')
const PALETTE = [
  '#6366f1', '#3b82f6', '#06b6d4', '#10b981', '#14b8a6',
  '#f59e0b', '#f97316', '#f43f5e', '#d946ef', '#8b5cf6',
  '#78716c', '#64748b',
]

function createAndAdd () {
  const label = query.value.trim()
  if (!label) return
  emit('create', { label, color: newColor.value })
  addTag(label)
  newColor.value = '#6b7280'
}

// ─── Inline edit popover ────────────────────────────────────────────────────
const editPop = ref(null) // { label, newLabel, color, x, y }

function openEdit (label, ev) {
  if (!props.canEdit) return
  ev.preventDefault()
  ev.stopPropagation()
  const tag = props.allTags.find(t => t.label === label || t.name === label)
  const rect = ev.currentTarget.getBoundingClientRect()
  editPop.value = {
    label,
    newLabel: label,
    color: tag?.color || props.getColor(label),
    category: tag?.category || 'Custom',
    x: rect.left,
    y: rect.bottom + 4,
  }
  nextTick(() => {
    const inp = document.querySelector('.te-edit-input')
    if (inp) inp.focus()
  })
}

function closeEdit () { editPop.value = null }

function saveEdit () {
  if (!editPop.value) return
  const { label, newLabel, color } = editPop.value
  if (newLabel.trim() && newLabel.trim() !== label) {
    emit('rename-tag', { oldName: label, newName: newLabel.trim() })
  }
  if (color !== (props.allTags.find(t => t.label === label)?.color)) {
    emit('update-tag', { name: newLabel.trim() || label, color })
  }
  closeEdit()
}

function deleteFromEdit () {
  if (!editPop.value) return
  emit('delete-tag', editPop.value.label)
  removeTag(editPop.value.label)
  closeEdit()
}

// ─── Keyboard nav ───────────────────────────────────────────────────────────
function onKeydown (e) {
  if (e.key === 'Enter' && query.value.trim()) {
    e.preventDefault()
    if (filtered.value.length) addTag(filtered.value[0].label)
    else if (showCreate.value) createAndAdd()
  }
  if (e.key === 'Backspace' && !query.value && _labels().length) {
    removeTag(_labels()[_labels().length - 1])
  }
  if (e.key === 'Escape') { focused.value = false; inputEl.value?.blur() }
}

function onBlur () {
  setTimeout(() => { focused.value = false }, 200)
}

// Close edit popover on outside click
function onEditBlur () {
  setTimeout(() => closeEdit(), 250)
}

// Autofocus optionnel : ouvre la liste d'autocomplétion dès l'apparition (ergonomie popover près du clic).
onMounted(() => { if (props.autofocus) nextTick(() => { inputEl.value?.focus(); focused.value = true }) })
</script>

<template>
<div class="te-wrap" :class="{ 'te-focused': focused, 'te-compact': compact, 'te-dark': isDark }">
  <!-- Existing tags as chips (glisser-déposer pour réordonner si sortable ; 1er chip = compétence PRINCIPALE) -->
  <draggable :model-value="modelValue" @update:model-value="onReorder" :item-key="_itemKey"
             :disabled="!sortable" :animation="150" tag="span" class="te-chips"
             filter=".te-chip-rm" :prevent-on-filter="false" ghost-class="te-chip-ghost">
    <template #item="{ element, index }">
      <span class="te-chip"
            :class="{ 'te-chip-required': showRequired && _isRequired(_lbl(element)), 'te-chip-sortable': sortable, 'te-chip-primary': sortable && index === 0 }"
            :style="'background:' + getColor(_lbl(element))"
            :title="sortable ? (index === 0 ? 'Compétence PRINCIPALE — glisser pour changer la priorité' : 'Glisser pour changer la priorité') : ''"
            @click.exact="canEdit ? openEdit(_lbl(element), $event) : null"
            @contextmenu="openEdit(_lbl(element), $event)">
        <span v-if="sortable && index === 0" class="te-chip-star" title="Compétence principale">&#x2605;</span>
        <span v-if="showRequired && _isRequired(_lbl(element))" class="te-pin" title="Requis">&#x1F4CC;</span>
        <span class="te-chip-label">{{ _lbl(element) }}</span>
        <span v-if="showLevel && _getLevel(_lbl(element))" class="te-chip-level" :class="'te-lvl-' + Math.min(_getLevel(_lbl(element)), 5)">{{ _getLevel(_lbl(element)) }}</span>
        <button class="te-chip-rm" @click.stop="removeTag(_lbl(element))">×</button>
      </span>
    </template>
  </draggable>
  <!-- Input -->
  <input ref="inputEl" class="te-input" type="text"
         v-model="query" :placeholder="modelValue.length ? '' : placeholder"
         @focus="focused = true" @blur="onBlur" @keydown="onKeydown" />
  <!-- Autocomplete dropdown -->
  <div v-if="focused && (filtered.length || showCreate)" class="te-dropdown">
    <div v-for="t in filtered" :key="t.label" class="te-option" @mousedown.prevent="addTag(t.label)">
      <span class="te-dot" :style="'background:' + (t.color || '#6b7280')"></span>
      <span class="te-opt-label">{{ t.label }}</span>
      <span class="te-opt-cat">{{ t.category }}</span>
    </div>
    <!-- Create new -->
    <div v-if="showCreate" class="te-create-section">
      <div class="te-create-row" @mousedown.prevent="createAndAdd">
        <span class="te-create-plus">+</span>
        <span>Créer « <strong>{{ query.trim() }}</strong> »</span>
      </div>
      <div class="te-palette" @mousedown.prevent>
        <button v-for="c in PALETTE" :key="c" class="te-pal-dot"
                :class="{ active: newColor === c }"
                :style="'background:' + c"
                @mousedown.prevent="newColor = c" />
      </div>
    </div>
  </div>

  <!-- Inline edit popover (contextmenu / dblclick) -->
  <Teleport to="body">
    <div v-if="editPop" class="te-edit-overlay" :class="{ 'te-dark': isDark }" @mousedown="closeEdit">
      <div class="te-edit-pop" :style="{ left: editPop.x + 'px', top: editPop.y + 'px' }"
           @mousedown.stop @blur="onEditBlur">
        <div class="te-edit-row">
          <input class="te-edit-input" v-model="editPop.newLabel"
                 @keydown.enter="saveEdit" @keydown.esc="closeEdit" />
        </div>
        <div class="te-edit-row">
          <span class="te-edit-label">Couleur</span>
          <div class="te-palette te-palette-sm">
            <button v-for="c in PALETTE" :key="c" class="te-pal-dot"
                    :class="{ active: editPop.color === c }"
                    :style="'background:' + c"
                    @click="editPop.color = c" />
          </div>
        </div>
        <div v-if="showLevel" class="te-edit-row">
          <span class="te-edit-label">{{ levelLabel }} <span class="te-edit-hint">{{ levelHint }}</span></span>
          <div class="te-level-btns">
            <button v-for="n in 5" :key="n" class="te-level-btn"
                    :class="{ active: _getLevel(editPop.label) === n, ['te-skill-' + n]: _getLevel(editPop.label) === n }"
                    @click="setLevel(editPop.label, n)">{{ n }}</button>
          </div>
        </div>
        <div v-if="showRequired" class="te-edit-row">
          <button class="te-req-toggle" :class="{ active: _isRequired(editPop.label) }"
                  @click="toggleRequired(editPop.label)">
            <span class="te-req-pin">&#x1F4CC;</span>
            {{ _isRequired(editPop.label) ? 'Requis' : 'Optionnel' }}
          </button>
        </div>
        <div class="te-edit-actions">
          <button class="te-btn te-btn-save" @click="saveEdit">Sauver</button>
          <button class="te-btn te-btn-del" @click="deleteFromEdit">Supprimer</button>
        </div>
      </div>
    </div>
  </Teleport>
</div>
</template>

<style scoped>
/* ─── Theme variables (light defaults, dark overrides below) ────────────── */
.te-wrap {
  --te-bg: #f8fafc;
  --te-border: rgba(0,0,0,0.1);
  --te-border-focus: rgba(99,102,241,0.5);
  --te-text: #1e293b;
  --te-text-muted: #64748b;
  --te-placeholder: #94a3b8;
  --te-dropdown-bg: #ffffff;
  --te-dropdown-border: rgba(99,102,241,0.3);
  --te-dropdown-shadow: rgba(0,0,0,0.12);
  --te-option-hover: rgba(99,102,241,0.08);
  --te-separator: rgba(0,0,0,0.06);
  --te-pop-bg: #ffffff;
  --te-pop-border: rgba(99,102,241,0.3);
  --te-pop-shadow: rgba(0,0,0,0.18);
  --te-input-bg: #f1f5f9;
  --te-input-border: rgba(0,0,0,0.12);
  --te-btn-border: rgba(0,0,0,0.12);
  --te-pal-active-border: #1e293b;
  --te-scrollbar: rgba(0,0,0,0.1);
}

.te-wrap {
  display:flex; flex-wrap:wrap; gap:3px; align-items:center;
  background:var(--te-bg); border:1px solid var(--te-border); border-radius:6px;
  padding:3px 6px; min-height:28px; position:relative; cursor:text;
  transition: border-color 0.12s;
}
.te-wrap.te-focused { border-color:var(--te-border-focus); }
.te-wrap.te-compact { min-height:22px; padding:2px 4px; }

/* Chips */
.te-chip {
  display:inline-flex; align-items:center; gap:2px;
  font-size:0.6rem; font-weight:600; color:#fff;
  padding:1px 6px; border-radius:10px; white-space:nowrap;
  cursor:default; user-select:none; transition: filter 0.1s;
}
.te-compact .te-chip { font-size:0.52rem; padding:0 5px; }
.te-chip:hover { filter:brightness(1.15); }
.te-chip-label { }
.te-chip-level {
  display:inline-flex; align-items:center; justify-content:center;
  width:13px; height:13px; border-radius:50%;
  background:rgba(0,0,0,0.3); font-size:0.5rem; font-weight:800;
  margin-left:2px;
}
/* Skill coloring: 1=basic(grey) → 5=expert(green) */
.te-lvl-1 { background:rgba(100,116,139,0.6); }
.te-lvl-2 { background:rgba(59,130,246,0.5); }
.te-lvl-3 { background:rgba(245,158,11,0.5); }
.te-lvl-4 { background:rgba(99,102,241,0.55); }
.te-lvl-5 { background:rgba(16,185,129,0.6); }
.te-chip-rm {
  background:none; border:none; color:rgba(255,255,255,0.55); cursor:pointer;
  font-size:0.7rem; padding:0 1px; margin-left:1px; line-height:1;
}
.te-chip-rm:hover { color:#fff; }
/* Réordonnancement (priorité) */
.te-chips { display:flex; flex-wrap:wrap; gap:3px; align-items:center; }
.te-chip-sortable { cursor:grab; }
.te-chip-sortable:active { cursor:grabbing; }
.te-chip-primary { box-shadow:0 0 0 1.5px rgba(250,204,21,0.95); }
.te-chip-star { font-size:0.6rem; line-height:1; color:#fde047; }
.te-chip-ghost { opacity:0.35; }

/* Input */
.te-input {
  flex:1; min-width:60px; background:none; border:none; outline:none;
  color:var(--te-text); font-size:0.72rem; padding:2px 0;
}
.te-input::placeholder { color:var(--te-placeholder); }

/* Dropdown */
.te-dropdown {
  position:absolute; top:100%; left:0; right:0; z-index:50;
  background:var(--te-dropdown-bg); border:1px solid var(--te-dropdown-border); border-radius:6px;
  max-height:220px; overflow-y:auto; box-shadow:0 8px 24px var(--te-dropdown-shadow);
  margin-top:2px;
}
.te-dropdown::-webkit-scrollbar { width:3px; }
.te-dropdown::-webkit-scrollbar-thumb { background:var(--te-scrollbar); }
.te-option {
  display:flex; align-items:center; gap:6px;
  padding:5px 10px; cursor:pointer; font-size:0.72rem; color:var(--te-text);
  transition:background 0.1s;
}
.te-option:hover { background:var(--te-option-hover); }
.te-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
.te-opt-label { flex:1; }
.te-opt-cat { font-size:0.55rem; color:var(--te-text-muted); }

/* Create section */
.te-create-section { border-top:1px solid var(--te-separator); }
.te-create-row {
  display:flex; align-items:center; gap:6px;
  padding:5px 10px; cursor:pointer; font-size:0.72rem; color:#6366f1; font-weight:600;
  transition:background 0.1s;
}
.te-create-row:hover { background:var(--te-option-hover); }
.te-create-plus {
  width:18px; height:18px; border-radius:50%; background:rgba(99,102,241,0.2);
  display:flex; align-items:center; justify-content:center;
  font-size:0.75rem; font-weight:800; color:#6366f1; flex-shrink:0;
}

/* Palette */
.te-palette { display:flex; gap:3px; padding:4px 10px 6px; flex-wrap:wrap; }
.te-palette-sm { padding:2px 0 0; }
.te-pal-dot {
  width:14px; height:14px; border-radius:50%; border:2px solid transparent;
  cursor:pointer; transition:border-color 0.1s, transform 0.1s;
}
.te-pal-dot.active { border-color:var(--te-pal-active-border); transform:scale(1.15); }
.te-pal-dot:hover { transform:scale(1.1); }

/* Edit popover (Teleport to body — uses :global for body-level styles) */
.te-edit-overlay {
  position:fixed; inset:0; z-index:9999;
}
.te-edit-pop {
  position:absolute; width:220px;
  background:var(--te-pop-bg); border:1px solid var(--te-pop-border); border-radius:8px;
  box-shadow:0 12px 32px var(--te-pop-shadow); padding:8px;
}
.te-edit-row { margin-bottom:6px; }
.te-edit-label { font-size:0.6rem; color:var(--te-text-muted); margin-bottom:2px; display:block; }
.te-edit-input {
  width:100%; background:var(--te-input-bg); border:1px solid var(--te-input-border);
  border-radius:4px; color:var(--te-text); font-size:0.75rem; padding:4px 6px; outline:none;
}
.te-edit-input:focus { border-color:rgba(99,102,241,0.5); }

/* Level buttons */
.te-level-btns { display:flex; gap:3px; }
.te-level-btn {
  width:22px; height:22px; border-radius:4px; border:1px solid var(--te-btn-border);
  background:var(--te-input-bg); color:var(--te-text-muted); font-size:0.6rem; font-weight:700;
  cursor:pointer; transition:all 0.1s;
}
.te-level-btn.active { background:rgba(99,102,241,0.25); color:#6366f1; border-color:rgba(99,102,241,0.4); }
.te-level-btn.active.te-skill-1 { background:rgba(100,116,139,0.2); color:#475569; border-color:rgba(100,116,139,0.4); }
.te-level-btn.active.te-skill-2 { background:rgba(59,130,246,0.15); color:#2563eb; border-color:rgba(59,130,246,0.4); }
.te-level-btn.active.te-skill-3 { background:rgba(245,158,11,0.15); color:#d97706; border-color:rgba(245,158,11,0.4); }
.te-level-btn.active.te-skill-4 { background:rgba(99,102,241,0.2); color:#6366f1; border-color:rgba(99,102,241,0.4); }
.te-level-btn.active.te-skill-5 { background:rgba(16,185,129,0.15); color:#059669; border-color:rgba(16,185,129,0.4); }
.te-level-btn:hover { border-color:rgba(99,102,241,0.4); }
.te-edit-hint { font-size:0.5rem; color:var(--te-text-muted); margin-left:4px; font-weight:400; }

/* Action buttons */
.te-edit-actions { display:flex; gap:6px; margin-top:6px; }
.te-btn {
  flex:1; padding:4px 8px; border-radius:4px; border:none;
  font-size:0.65rem; font-weight:600; cursor:pointer; transition:all 0.1s;
}
.te-btn-save { background:rgba(99,102,241,0.15); color:#6366f1; }
.te-btn-save:hover { background:rgba(99,102,241,0.25); }
.te-btn-del { background:rgba(239,68,68,0.08); color:#dc2626; }
.te-btn-del:hover { background:rgba(239,68,68,0.18); }

/* Required pin on chips */
.te-pin { font-size:0.5rem; margin-right:1px; filter:saturate(0.7); }
.te-chip-required { outline:1.5px solid rgba(255,255,255,0.35); outline-offset:-1px; }

/* Required toggle button in popover */
.te-req-toggle {
  display:flex; align-items:center; gap:4px; width:100%;
  padding:5px 8px; border-radius:4px; border:1px solid var(--te-btn-border);
  background:var(--te-input-bg); color:var(--te-text-muted); font-size:0.65rem; font-weight:600;
  cursor:pointer; transition:all 0.15s;
}
.te-req-toggle:hover { border-color:rgba(245,158,11,0.4); }
.te-req-toggle.active { background:rgba(245,158,11,0.12); color:#d97706; border-color:rgba(245,158,11,0.4); }
.te-req-pin { font-size:0.7rem; }

/* ─── Dark theme overrides (driven by .te-dark class from useQuasar) ───── */
.te-dark {
  --te-bg: #181c2e;
  --te-border: rgba(255,255,255,0.06);
  --te-border-focus: rgba(99,102,241,0.4);
  --te-text: #e2e4ef;
  --te-text-muted: #7b80a0;
  --te-placeholder: #7b80a0;
  --te-dropdown-bg: #181c2e;
  --te-dropdown-border: rgba(99,102,241,0.3);
  --te-dropdown-shadow: rgba(0,0,0,0.45);
  --te-option-hover: rgba(99,102,241,0.12);
  --te-separator: rgba(255,255,255,0.06);
  --te-pop-bg: #1e2235;
  --te-pop-border: rgba(99,102,241,0.35);
  --te-pop-shadow: rgba(0,0,0,0.55);
  --te-input-bg: #181c2e;
  --te-input-border: rgba(255,255,255,0.1);
  --te-btn-border: rgba(255,255,255,0.1);
  --te-pal-active-border: #fff;
  --te-scrollbar: rgba(255,255,255,0.1);
}
.te-dark .te-btn-save { color:#a5b4fc; }
.te-dark .te-btn-del { color:#fca5a5; }
.te-dark .te-level-btn.active { color:#a5b4fc; }
.te-dark .te-level-btn.active.te-skill-1 { color:#cbd5e1; }
.te-dark .te-level-btn.active.te-skill-2 { color:#93c5fd; }
.te-dark .te-level-btn.active.te-skill-3 { color:#fcd34d; }
.te-dark .te-level-btn.active.te-skill-4 { color:#a5b4fc; }
.te-dark .te-level-btn.active.te-skill-5 { color:#6ee7b7; }
.te-dark .te-req-toggle.active { color:#fcd34d; }
</style>
