// ─────────────────────────────────────────────────────────────────────────────
// Shared client-side JS baked into every magic-link page.
// Exposes: $, esc, toast, fmtTime, dlbl, api, router, go
// Configure via window.UI_CFG = { token, hub, today, base } BEFORE this loads.
// ─────────────────────────────────────────────────────────────────────────────
(function () {
  var CFG = window.UI_CFG || {}
  var HUB  = CFG.hub || ''
  var BASE = CFG.base || ''   // e.g. "/t/<token>" — prepended to all api paths

  // ── DOM / string ────────────────────────────────────────────────────────
  function $ (id) { return document.getElementById(id) }
  function esc (s) {
    return (s == null ? '' : String(s))
      .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;').replace(/'/g, '&#39;')
  }

  // ── Toast ───────────────────────────────────────────────────────────────
  function toast (message, ok) {
    var t = $('toast')
    if (!t) {
      t = document.createElement('div')
      t.id = 'toast'
      t.className = 'toast'
      document.body.appendChild(t)
    }
    t.textContent = message
    t.style.background = ok ? '#22c55e' : '#ef4444'
    t.classList.add('on')
    clearTimeout(t._timer)
    t._timer = setTimeout(function () { t.classList.remove('on') }, 2500)
  }

  // ── Date / time (mirror of server helpers) ──────────────────────────────
  function fmtTime (t) {
    if (!t) return ''
    var p = String(t).split(':')
    return p[0] + 'h' + (p[1] || '00')
  }
  function dlbl (d, today) {
    today = today || CFG.today
    if (!d) return 'Sans date'
    if (d === today) return "Aujourd'hui"
    try {
      var diff = Math.round((new Date(d + 'T00:00:00') - new Date(today + 'T00:00:00')) / 86400000)
      if (diff === -1) return 'Hier'
      if (diff === 1)  return 'Demain'
      return new Date(d + 'T00:00:00').toLocaleDateString('fr-CA', { weekday: 'short', day: 'numeric', month: 'short' })
    } catch (e) { return d }
  }

  // ── API wrapper ─────────────────────────────────────────────────────────
  // Single place to prepend HUB+BASE and parse JSON. Page-specific code
  // just does api.post('/note', {job, notes}) — no URL glue, no error swallowing.
  function apiUrl (path) {
    // Allow absolute paths through unchanged (e.g. fully qualified URLs)
    if (/^https?:/i.test(path)) return path
    if (path[0] !== '/') path = '/' + path
    return HUB + BASE + path
  }
  function apiFetch (path, opts) {
    opts = opts || {}
    var headers = Object.assign({}, opts.headers || {})
    if (opts.body && typeof opts.body === 'object' && !(opts.body instanceof FormData)) {
      headers['Content-Type'] = headers['Content-Type'] || 'application/json'
      opts.body = JSON.stringify(opts.body)
    }
    opts.headers = headers
    return fetch(apiUrl(path), opts).then(function (r) {
      var ct = r.headers.get('content-type') || ''
      if (ct.indexOf('application/json') >= 0) {
        return r.json().then(function (data) { return { ok: r.ok, status: r.status, data: data } })
      }
      return r.text().then(function (text) { return { ok: r.ok, status: r.status, text: text } })
    })
  }
  var api = {
    url:  apiUrl,
    get:  function (p)      { return apiFetch(p) },
    post: function (p, body){ return apiFetch(p, { method: 'POST', body: body }) },
    put:  function (p, body){ return apiFetch(p, { method: 'PUT',  body: body }) },
  }

  // ── Hash router ─────────────────────────────────────────────────────────
  // Patterns: "#home" (literal) or "#job/:name" (param). Handlers are called
  // with (params, rawHash). Calling router.go('#foo') updates location.hash.
  var routes = []
  function on (pattern, handler) { routes.push({ pattern: pattern, handler: handler }) }
  function matchRoute (hash) {
    for (var i = 0; i < routes.length; i++) {
      var r = routes[i]
      if (r.pattern === hash) return { handler: r.handler, params: {} }
      // "#job/:name" — matches "#job/DJ-123"
      var parts = r.pattern.split('/')
      var actual = hash.split('/')
      if (parts.length !== actual.length) continue
      var params = {}, ok = true
      for (var j = 0; j < parts.length; j++) {
        if (parts[j][0] === ':') params[parts[j].slice(1)] = decodeURIComponent(actual[j] || '')
        else if (parts[j] !== actual[j]) { ok = false; break }
      }
      if (ok) return { handler: r.handler, params: params }
    }
    return null
  }
  function dispatch () {
    var hash = location.hash || (routes[0] && routes[0].pattern) || '#'
    var m = matchRoute(hash)
    if (m) { m.handler(m.params, hash) }
    else if (routes[0]) { routes[0].handler({}, routes[0].pattern) }
    window.scrollTo(0, 0)
  }
  function go (hash) {
    if (location.hash === hash) dispatch()
    else location.hash = hash
  }
  window.addEventListener('hashchange', dispatch)

  var router = { on: on, dispatch: dispatch, go: go }

  // ── Expose globals (only ones pages reference directly) ─────────────────
  window.$      = $
  window._esc   = esc       // underscore to avoid colliding with page esc
  window.toast  = toast
  window.fmtTime = fmtTime
  window.dlbl   = dlbl
  window.api    = api
  window.router = router
  window.go     = go
})()
