'use strict'
// ─────────────────────────────────────────────────────────────────────────────
// Server-side HTML fragment builders for magic-link pages.
// Pure functions returning strings. Pairs with ui/design.css classes.
// ─────────────────────────────────────────────────────────────────────────────

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

// Safely inline JSON in a <script> tag (blocks </script> + --> breakouts)
function jsonScript (value) {
  return JSON.stringify(value).replace(/</g, '\\u003c').replace(/-->/g, '--\\u003e')
}

// ── Canonical status metadata ─────────────────────────────────────────────
// One source of truth for FR labels + colors. Both tech mobile and detail
// views read from this so a status rename propagates everywhere.
const STATUS_META = {
  Scheduled:     { label: 'Planifié',  color: '#818cf8' },
  assigned:      { label: 'Assigné',   color: '#818cf8' },
  open:          { label: 'Ouvert',    color: '#818cf8' },
  'In Progress': { label: 'En cours',  color: '#f59e0b' },
  in_progress:   { label: 'En cours',  color: '#f59e0b' },
  Completed:     { label: 'Terminé',   color: '#22c55e' },
  Cancelled:     { label: 'Annulé',    color: '#94a3b8' },
}

function statusMeta (s) {
  return STATUS_META[s] || { label: s || '—', color: '#94a3b8' }
}

function badge (status) {
  const m = statusMeta(status)
  return `<span class="bdg" style="background:${m.color}22;color:${m.color}">${esc(m.label)}</span>`
}

// ── Section with count pill ───────────────────────────────────────────────
// title:   human heading, e.g. "En retard"
// items:   array of pre-rendered HTML strings (from jobCard() or similar)
// modifier: 'danger' | '' — adds .sec.danger for red accent
function section (title, items, modifier = '') {
  if (!items.length) return ''
  const mod = modifier ? ' ' + modifier : ''
  return `<div class="sec${mod}">${esc(title)} <span class="cnt">${items.length}</span></div>${items.join('')}`
}

// ── Primitive wrappers ────────────────────────────────────────────────────
function card (inner, { onclick, extraClass = '', style = '' } = {}) {
  const cls = 'card' + (extraClass ? ' ' + extraClass : '')
  const click = onclick ? ` onclick="${onclick}"` : ''
  const st = style ? ` style="${style}"` : ''
  return `<div class="${cls}"${click}${st}>${inner}</div>`
}

function panel (title, bodyHtml, { extra = '' } = {}) {
  return `<div class="panel"><h3>${esc(title)}${extra ? ` <span class="rt">${extra}</span>` : ''}</h3>${bodyHtml}</div>`
}

function emptyState (emoji, message) {
  return `<div class="empty"><div class="em">${esc(emoji)}</div><p>${message}</p></div>`
}

function placeholder (emoji, title, body) {
  return `<div class="placeholder"><div class="em">${esc(emoji)}</div><h2>${esc(title)}</h2><p>${body}</p></div>`
}

function button (label, { kind = 'pri', onclick, id, block = false, extraClass = '', disabled = false, style = '' } = {}) {
  const cls = ['btn', 'btn-' + kind, block ? 'btn-block' : '', extraClass].filter(Boolean).join(' ')
  return `<button class="${cls}"${id ? ` id="${id}"` : ''}${onclick ? ` onclick="${onclick}"` : ''}${disabled ? ' disabled' : ''}${style ? ` style="${style}"` : ''}>${label}</button>`
}

// ── Stat row (inside header) ──────────────────────────────────────────────
// items: [{ value, label, onclick? }]
function statRow (items) {
  return `<div class="sts">${items.map(it => {
    const click = it.onclick ? ` onclick="${it.onclick}"` : ''
    const id = it.id ? ` id="${it.id}"` : ''
    return `<div class="st"${click}><b${id}>${esc(it.value)}</b><small>${esc(it.label)}</small></div>`
  }).join('')}</div>`
}

// ── Tab bar ───────────────────────────────────────────────────────────────
// tabs: [{ id, label, icon, active? }]
function tabBar (tabs) {
  return `<div class="tbar">${tabs.map(t => {
    const cls = 'tab' + (t.active ? ' on' : '')
    return `<button class="${cls}" data-v="${esc(t.id)}" onclick="go('#${esc(t.id)}')"><span class="ic">${esc(t.icon)}</span>${esc(t.label)}</button>`
  }).join('')}</div>`
}

// ── Date / time helpers ───────────────────────────────────────────────────
function fmtTime (t) {
  if (!t) return ''
  const [h, m] = String(t).split(':')
  return `${h}h${m || '00'}`
}

function fmtDate (d) {
  if (!d) return ''
  try { return new Date(d + 'T00:00:00').toLocaleDateString('fr-CA', { weekday: 'short', day: 'numeric', month: 'short' }) }
  catch { return d }
}

// "Aujourd'hui" / "Hier" / "Demain" / weekday / date
function dateLabelFr (d, today) {
  if (!d) return 'Sans date'
  if (d === today) return "Aujourd'hui"
  try {
    const 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'
    if (diff > 1 && diff <= 6) return new Date(d + 'T00:00:00').toLocaleDateString('fr-CA', { weekday: 'long' })
    return fmtDate(d)
  } catch { return fmtDate(d) }
}

function todayFr () {
  return new Date().toLocaleDateString('fr-CA', { weekday: 'long', day: 'numeric', month: 'long' })
}

// YYYY-MM-DD in America/Montreal regardless of server TZ
function montrealDate (d = new Date()) {
  return d.toLocaleDateString('en-CA', { timeZone: 'America/Montreal', year: 'numeric', month: '2-digit', day: '2-digit' })
}

module.exports = {
  esc, jsonScript,
  STATUS_META, statusMeta, badge,
  section, card, panel, emptyState, placeholder, button, statRow, tabBar,
  fmtTime, fmtDate, dateLabelFr, todayFr, montrealDate,
}
