// ── useTagCatalog ─────────────────────────────────────────────────────────────
// SOURCE UNIQUE des étiquettes de ticket. Avant : les tags de ticket venaient du
// seul doctype ERPNext « Dispatch Tag » (liste seedée à part) — les vraies
// compétences roster (« sans-fil », « fusionneur »…) en étaient absentes. Ici on
// UNIFIE : Dispatch Tag ∪ compétences des techniciens (roster hub). Le même
// catalogue alimente TagEditor sur la fiche ticket (IssueDetail) que sur la
// Planification, cohérent avec « reason chips liés aux compétences ».
//
// Format de sortie (allTags) attendu par TagEditor : [{ name, label, color, category }].
import { ref, computed } from 'vue'
import { fetchTags, createTag as apiCreateTag, updateTag as apiUpdateTag, renameTag as apiRenameTag, deleteTag as apiDeleteTag } from 'src/api/dispatch'
import { listTechnicians } from 'src/api/roster'

// Même palette / hash que PlanificationPage → une compétence a la MÊME couleur
// partout, qu'elle ait ou non un enregistrement Dispatch Tag.
const TAG_PALETTE = [
  '#6366f1', '#3b82f6', '#0ea5e9', '#06b6d4', '#14b8a6', '#10b981', '#22c55e', '#84cc16',
  '#eab308', '#f59e0b', '#f97316', '#ef4444', '#f43f5e', '#fb7185', '#ec4899', '#f472b6',
  '#db2777', '#d946ef', '#a855f7', '#8b5cf6', '#78716c', '#64748b', '#94a3b8', '#111827',
]
function hashColor (label) { let h = 0; for (const c of String(label)) h = (h * 31 + c.charCodeAt(0)) >>> 0; return TAG_PALETTE[h % TAG_PALETTE.length] }
// Couleurs de compétences créées à la volée (partagées avec la Planification).
function readCustomColors () { try { return JSON.parse(localStorage.getItem('roster-skill-tags-v1') || '[]') } catch { return [] } }

// Cache au niveau module : les ouvertures répétées du panneau ticket ne
// refont pas les requêtes (Dispatch Tag + techniciens). reload() force.
const _dispatchTags = ref([])   // [{ name, label, color, category }]
const _rosterSkills = ref([])   // ['sans-fil', 'fusionneur', …]
let _loaded = false
let _inflight = null

async function _load () {
  const [tags, techs] = await Promise.all([
    fetchTags().catch(() => []),
    listTechnicians().catch(() => ({})),
  ])
  _dispatchTags.value = Array.isArray(tags) ? tags : []
  const list = Array.isArray(techs) ? techs : (techs && Array.isArray(techs.technicians) ? techs.technicians : [])
  const skills = new Set()
  for (const t of list) for (const s of (t && Array.isArray(t.skills) ? t.skills : [])) { const v = String(s || '').trim(); if (v) skills.add(v) }
  _rosterSkills.value = [...skills]
  _loaded = true
}

export function useTagCatalog () {
  const loading = ref(false)

  const dispatchTags = _dispatchTags // exposé pour le gestionnaire de tags (CRUD Dispatch Tag)

  // Catalogue unifié : Dispatch Tags d'abord (ils portent une couleur/catégorie),
  // puis les compétences roster non déjà présentes (couleur = custom LS ou hash).
  const allTags = computed(() => {
    const m = new Map()
    for (const t of _dispatchTags.value) {
      const label = t.label || t.name
      const key = String(label || '').toLowerCase()
      if (!key) continue
      m.set(key, { name: t.name, label, color: t.color || '#6b7280', category: t.category || 'Dispatch' })
    }
    const custom = readCustomColors()
    for (const s of _rosterSkills.value) {
      const key = String(s).toLowerCase()
      if (m.has(key)) continue
      const c = custom.find(x => String(x.label).toLowerCase() === key)
      m.set(key, { name: s, label: s, color: (c && c.color) || hashColor(s), category: 'Compétence' })
    }
    return [...m.values()].sort((a, b) => a.label.localeCompare(b.label))
  })

  function getColor (label) {
    const key = String(label || '').toLowerCase()
    const t = allTags.value.find(x => x.label.toLowerCase() === key || x.name.toLowerCase() === key)
    return (t && t.color) || hashColor(label)
  }

  async function load (force = false) {
    if (_loaded && !force) return
    loading.value = true
    try { _inflight = _inflight && !force ? _inflight : _load(); await _inflight } finally { _inflight = null; loading.value = false }
  }
  const reload = () => load(true)

  // ── CRUD Dispatch Tag (le gestionnaire de tags agit sur ces enregistrements) ──
  // Une compétence roster PURE n'a pas d'enregistrement Dispatch Tag : on en crée
  // un à la volée si on la (re)colore/renomme, pour la matérialiser une fois.
  async function createTag (label, color) {
    const rec = await apiCreateTag(label, 'Custom', color || hashColor(label))
    const norm = { name: rec?.name || label, label: rec?.label || label, color: rec?.color || color || hashColor(label), category: rec?.category || 'Custom' }
    if (!_dispatchTags.value.some(t => (t.label || t.name) === norm.label)) _dispatchTags.value = [..._dispatchTags.value, norm]
    return norm
  }
  async function recolorTag (t, color) {
    const existing = _dispatchTags.value.find(x => x.name === t.name || x.label === t.label)
    if (!existing) { await createTag(t.label || t.name, color); return }
    await apiUpdateTag(existing.name, { color })
    existing.color = color
  }
  async function renameTag (t, newLabel) {
    const existing = _dispatchTags.value.find(x => x.name === t.name || x.label === t.label)
    if (!existing) { await createTag(newLabel, t.color); return newLabel }
    await apiRenameTag(existing.name, newLabel)
    existing.label = newLabel; existing.name = newLabel
    return newLabel
  }
  async function removeTag (t) {
    const existing = _dispatchTags.value.find(x => x.name === t.name || x.label === t.label)
    if (existing) await apiDeleteTag(existing.name)
    _dispatchTags.value = _dispatchTags.value.filter(x => x.name !== (existing?.name || t.name))
  }

  return { allTags, dispatchTags, getColor, loading, load, reload, createTag, recolorTag, renameTag, removeTag }
}
