/**
 * useAssignment — composable d'assignation UNIFIÉE (le SEUL point d'écriture
 * job→tech, partagé par le board Dispatch ET la grille Planification).
 * -----------------------------------------------------------------------------
 * Les vues appellent assign/reorder/unassign/setTeam — JAMAIS updateJob() direct.
 * Le composable est agnostique du store : la vue fournit ses hooks optimistes.
 *
 *   const A = useAssignment({
 *     onError: (e) => $q.notify({ type:'negative', message:String(e) }),
 *     onLocal: (fn) => fn(),   // appliquer une MAJ locale optimiste (selon le store)
 *   })
 *   await A.assign(jobName, techId, '2026-06-10')
 *
 * `assigned_tech` = clé d'identité tech NORMALISÉE (voir useResources.techKey) :
 * on passe l'id tech ; le hub résout le docname Dispatch Technician.
 */
import * as api from '../api/assignment'

// Sérialise une liste d'assistants (modèle front {techId,...} OU déjà {tech_id,...}) → format hub/ERPNext.
export function serializeAssistants (assistants) {
  return (assistants || []).map(a => ({
    tech_id: a.techId ?? a.tech_id,
    tech_name: a.techName ?? a.tech_name ?? '',
    duration_h: a.duration ?? a.duration_h ?? null,
    note: a.note || '',
    pinned: a.pinned ? 1 : 0,
  }))
}

const aid = (a) => a && (a.techId ?? a.tech_id)

export function useAssignment (opts = {}) {
  const onErr = opts.onError || ((e) => console.error('[assignment]', e))
  const local = opts.onLocal || ((fn) => { try { fn && fn() } catch (e) { /* noop */ } })

  async function run (fn, optimistic) {
    if (optimistic) local(optimistic)        // MAJ optimiste immédiate (UX réactive)
    try { return await fn() } catch (e) { onErr(e); throw e }
  }

  // Assigner job→tech sur une date (option optimistic = closure de MAJ locale).
  const assign = (job, tech, date, optimistic) => run(() => api.assign(job, tech, date), optimistic)
  // Réordonner : updates = [{ job, route_order, priority? }].
  const reorder = (updates, optimistic) => run(() => api.reorder(updates), optimistic)
  // Désassigner (retour au pool).
  const unassign = (job, optimistic) => run(() => api.unassign(job), optimistic)
  // Remplacer l'équipe complète d'un job.
  const setTeam = (job, assistants, optimistic) => run(() => api.setTeam(job, serializeAssistants(assistants)), optimistic)

  // Ajouter un assistant (dédupe par tech) — `current` = liste actuelle d'assistants du job.
  function addAssistant (job, current, assistant, optimistic) {
    const next = [...(current || []).filter(a => aid(a) !== aid(assistant)), assistant]
    return setTeam(job, next, optimistic)
  }
  // Retirer un assistant par id tech.
  function removeAssistant (job, current, techId, optimistic) {
    const next = (current || []).filter(a => aid(a) !== techId)
    return setTeam(job, next, optimistic)
  }

  return { assign, reorder, unassign, setTeam, addAssistant, removeAssistant }
}
