/**
 * Shared formatting utilities for the ops app.
 * Used in ClientDetailPage, TicketsPage, and future pages.
 */

const ERP_BASE = 'https://erp.gigafibre.ca'

/**
 * Format a date string to fr-CA short format (e.g. "30 mars 2026")
 * @param {string|null} d - Date string (ISO or YYYY-MM-DD)
 * @returns {string}
 */
export function formatDate (d) {
  if (!d) return '—'
  const dt = new Date(d)
  if (isNaN(dt.getTime())) return '—' // jamais « Invalid Date » : date absente/illisible → tiret
  return dt.toLocaleDateString('fr-CA', { year: 'numeric', month: 'short', day: 'numeric' })
}

/**
 * Format a date string to DD/MM/YYYY
 * @param {string|null} d - Date string
 * @returns {string}
 */
export function formatDateShort (d) {
  if (!d) return '—'
  const str = String(d).slice(0, 10)
  if (str.length < 10) return str
  const [y, m, day] = str.split('-')
  return `${day}/${m}/${y}`
}

/**
 * Format a number as CAD currency
 * @param {number} v
 * @returns {string}
 */
export function formatMoney (v) {
  return (v || 0).toLocaleString('fr-CA', { style: 'currency', currency: 'CAD' })
}

/**
 * Build a link to the ERPNext desk for a doctype + name
 * @param {string} doctype - e.g. 'Sales Invoice', 'Issue'
 * @param {string} name - Document name/ID
 * @returns {string}
 */
export function erpLink (doctype, name) {
  if (!doctype || !name) return '#'
  return ERP_BASE + '/app/' + doctype.toLowerCase().replace(/ /g, '-') + '/' + encodeURIComponent(name)
}

/**
 * Build a full URL for an ERPNext file attachment
 * @param {string} url - Relative or absolute file URL
 * @returns {string}
 */
export function erpFileUrl (url) {
  if (!url) return '#'
  if (url.startsWith('http')) return url
  return ERP_BASE + url
}

export function formatDateTime (dt) {
  if (!dt) return ''
  const d = new Date(dt)
  if (isNaN(d)) return dt
  return d.toLocaleDateString('fr-CA', { year: 'numeric', month: 'short', day: 'numeric' }) + ' ' +
    d.toLocaleTimeString('fr-CA', { hour: '2-digit', minute: '2-digit' })
}

// ═══ Staff avatar helpers ═══

const AVATAR_COLORS = ['#4f46e5','#0891b2','#059669','#d97706','#dc2626','#7c3aed','#be185d','#0d9488','#6366f1','#ea580c']

/**
 * Generate a consistent color from a name string (for avatar backgrounds).
 * @param {string|null} name
 * @returns {string} Hex color
 */
export function staffColor (name) {
  if (!name) return '#9e9e9e'
  let h = 0
  for (let i = 0; i < name.length; i++) h = name.charCodeAt(i) + ((h << 5) - h)
  return AVATAR_COLORS[Math.abs(h) % AVATAR_COLORS.length]
}

/**
 * Extract initials from a full name string.
 * @param {string|null} name
 * @returns {string}
 */
export function staffInitials (name) {
  if (!name) return ''
  const parts = name.trim().split(/\s+/)
  if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase()
  return parts[0].substring(0, 2).toUpperCase()
}

/**
 * Decode HTML entities (&#039; -> ', &amp; -> &, etc.)
 * @param {string|null} str
 * @returns {string}
 */
export function decodeHtml (str) {
  if (!str) return str
  const el = document.createElement('textarea')
  el.innerHTML = str
  return el.value
}

/**
 * Extract display name from email (user@domain -> User)
 * @param {string|null} email
 * @returns {string}
 */
// Roster d'équipe (courriel → NOM COMPLET réel), peuplé au chargement des agents (useConversations.fetchAgents → /conversations/agents).
// Permet d'AFFICHER et de RECHERCHER « Michel Blais » plutôt que le seul préfixe courriel « michel » dans l'assignation et les @mentions.
const AGENT_ROSTER = {}
export function setAgentRoster (map) { if (map && typeof map === 'object') for (const k of Object.keys(map)) if (map[k]) AGENT_ROSTER[String(k).toLowerCase()] = map[k] }

export function noteAuthorName (email) {
  if (!email) return 'Système'
  const real = AGENT_ROSTER[String(email).toLowerCase()]
  if (real) return real
  const local = email.split('@')[0]
  return local.charAt(0).toUpperCase() + local.slice(1).replace(/[._-]/g, ' ')
}

/**
 * Relative time display for notes/comments.
 * @param {string|null} d - Date/datetime string
 * @returns {string}
 */
export function noteTimeAgo (d) {
  if (!d) return ''
  const diff = Date.now() - new Date(d).getTime()
  const mins = Math.floor(diff / 60000)
  if (mins < 1) return "À l'instant"
  if (mins < 60) return `Il y a ${mins} min`
  const hours = Math.floor(mins / 60)
  if (hours < 24) return `Il y a ${hours}h`
  const days = Math.floor(hours / 24)
  if (days < 7) return `Il y a ${days}j`
  return formatDate(d)
}

// ═══ Canonical helpers (consolidation target — see docs/UI_AND_OPTIMIZATION.md §D) ═══

/**
 * Email → short agent handle (local part). Canonical replacement for the ~5 private
 * `shortAgent` copies across conversation/board components.
 * @param {string|null} email
 * @returns {string}
 */
export function shortAgent (email) {
  return String(email || '').split('@')[0]
}

/**
 * Compact time of day "9h05" (fr). Used by tech list/cards.
 * @param {string|number|Date|null} t
 * @returns {string}
 */
export function fmtTimeHHhMM (t) {
  if (!t) return ''
  const d = new Date(t)
  if (isNaN(d.getTime())) return ''
  return `${d.getHours()}h${String(d.getMinutes()).padStart(2, '0')}`
}

/**
 * Relative timestamp: today → "14:32", otherwise → "13/06" (fr-CA).
 * Canonical target for the divergent inbox/board `formatTime` copies.
 * @param {string|number|Date|null} ts
 * @returns {string}
 */
export function relTime (ts) {
  if (!ts) return ''
  const dt = new Date(ts)
  if (isNaN(dt.getTime())) return ''
  const now = new Date()
  return dt.toDateString() === now.toDateString()
    ? dt.toLocaleTimeString('fr-CA', { hour: '2-digit', minute: '2-digit' })
    : dt.toLocaleDateString('fr-CA', { day: '2-digit', month: '2-digit' })
}

/**
 * Short date+time, e.g. "2026-06-13 14:32" (fr-CA). Accepts ISO or "YYYY-MM-DD HH:MM:SS".
 * Canonical target for the ~6 `fmtTime`/`fmt`/`fmtTs` copies. Returns '' on empty/invalid.
 * @param {string|number|Date|null} d
 * @returns {string}
 */
export function formatDateTimeShort (d) {
  if (!d) return ''
  const dt = new Date(String(d).replace(' ', 'T'))
  if (isNaN(dt.getTime())) return ''
  return dt.toLocaleString('fr-CA', { dateStyle: 'short', timeStyle: 'short' })
}

// ── Formateurs canoniques dé-dupliqués (audit T1 2026-07-04) — remplacent des copies locales IDENTIQUES ──
// Initiales = 2 PREMIERS mots (« Jean Bourdon » → « JB »), '?' si vide. ⚠ DIFFÉRENT de staffInitials (1er + DERNIER mot).
// Version « 2 premiers » = celle de la grille Planif + carte des tournées.
export function initials (name) {
  return String(name || '').split(/\s+/).filter(Boolean).map(w => w[0]).slice(0, 2).join('').toUpperCase() || '?'
}
// Heure d'horloge : chaîne « 8:30 » → « 8h30 ». ⚠ DIFFÉRENT de fmtTimeHHhMM (qui prend un Date).
export function fmtClock (t) { if (!t) return ''; const [h, m] = String(t).split(':'); return `${h}h${m}` }
// Date « longue » : « 3 juillet 2026 » ; '' si absent.
export function formatDateLong (d) {
  return d ? new Date(d).toLocaleDateString('fr-CA', { day: 'numeric', month: 'long', year: 'numeric' }) : ''
}
