'use strict'
const cfg = require('./config')
const { log } = require('./helpers')
const erp = require('./erp')
const { broadcastAll } = require('./sse')

// Lazy require to avoid circular dependency with twilio.js
function sendSmsInternal (phone, message) {
  return require('./twilio').sendSmsInternal(phone, message)
}

// ── Date helpers ──

const DAY_NAMES = { lun: 1, lundi: 1, mar: 2, mardi: 2, mer: 3, mercredi: 3, jeu: 4, jeudi: 4, ven: 5, vendredi: 5, sam: 6, samedi: 6, dim: 0, dimanche: 0 }

function localDateStr (d) {
  return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0')
}

function addDays (d, n) {
  const r = new Date(d); r.setDate(r.getDate() + n); return r
}

function nextWeekday (dayNum) {
  const now = new Date()
  let diff = dayNum - now.getDay()
  if (diff <= 0) diff += 7
  return addDays(now, diff)
}

// ── ERPNext helpers ──

async function lookupTechByPhone (phone) {
  const digits = phone.replace(/\D/g, '').slice(-10)
  // Build a LIKE pattern that matches digits regardless of separators (dashes, spaces, dots)
  // e.g. 5149490739 → %514%949%0739%
  const pattern = '%' + digits.replace(/(\d{3})(\d{3})(\d{4})/, '$1%$2%$3') + '%'
  const rows = await erp.list('Dispatch Technician', {
    fields: ['name', 'full_name', 'phone', 'status'],
    filters: [['phone', 'like', pattern]],
    limit: 1,
  })
  return rows[0] || null
}

async function setTechAbsence (techName, { from, until, startTime, endTime, reason }) {
  const body = {
    status: 'En pause',
    absence_from: from,
    absence_until: until || from,
    absence_reason: reason || 'personal',
    absence_start_time: startTime || '',
    absence_end_time: endTime || '',
  }
  const res = await erp.update('Dispatch Technician', techName, body)
  if (res.ok) {
    log(`Tech absence set: ${techName} from=${from} until=${until || from}`)
    broadcastAll('tech-absence', { techName, action: 'set', from, until: until || from, startTime, endTime, reason })
    return true
  }
  log(`Tech absence set FAILED: ${techName}`, res.error)
  return false
}

async function clearTechAbsence (techName) {
  const body = {
    status: 'Disponible',
    absence_from: '', absence_until: '', absence_reason: '',
    absence_start_time: '', absence_end_time: '',
  }
  const res = await erp.update('Dispatch Technician', techName, body)
  if (res.ok) {
    log(`Tech absence cleared: ${techName}`)
    broadcastAll('tech-absence', { techName, action: 'clear' })
    return true
  }
  log(`Tech absence clear FAILED: ${techName}`, res.error)
  return false
}

// ── LLM parsing (Gemini Flash via OpenAI-compatible API) ──

function buildSystemPrompt () {
  return `Tu es un assistant qui analyse les SMS reçus d'une personne qui est TECHNICIEN TERRAIN et possiblement aussi CLIENT de l'entreprise (FAI/télécoms).
Aujourd'hui: ${localDateStr(new Date())}

CONTEXTE IMPORTANT: Cette personne a deux rôles possibles:
- Employé/technicien: messages liés au travail, présence, absences, disponibilité
- Client: messages liés à son service internet, facturation, problèmes techniques personnels

Tu dois déterminer si le message concerne le RÔLE EMPLOYÉ ou le RÔLE CLIENT.

Retourne UNIQUEMENT du JSON valide, rien d'autre.

Si le message concerne une ABSENCE EMPLOYÉ:
{"action":"absent","from":"YYYY-MM-DD","until":"YYYY-MM-DD","startTime":"HH:MM or null","endTime":"HH:MM or null","reason":"personal|medical|family|training|other","fullDay":true/false}

Si c'est un RETOUR au travail:
{"action":"retour"}

Si le message concerne le RÔLE CLIENT (problème internet, facture, service) ou n'est PAS lié au travail:
{"action":"none"}

EXEMPLES employé → absent/retour:
- "absent demain" → absent
- "je serai pas là vendredi" → absent
- "malade" → absent, medical
- "rdv dentiste 14h-16h" → absent partiel, medical
- "formation jeudi" → absent, training
- "mon fils est malade je reste à la maison" → absent, family
- "retour", "dispo", "de retour" → retour

EXEMPLES client → none:
- "mon internet est lent" → none (problème de service client)
- "j'ai pas reçu ma facture" → none (facturation client)
- "mon wifi ne marche plus" → none (support technique client)
- "je veux changer mon forfait" → none (demande client)
- "salut, as-tu le numéro du client?" → none (conversation générale)

Règles dates:
- "absent" sans date = aujourd'hui
- "demain" = jour suivant
- "lundi/mardi/..." = prochain jour nommé
- "3j" ou "3 jours" = aujourd'hui + n-1 jours
- startTime/endTime = null si journée complète
- Heures au format 24h (HH:MM)`
}

// Analyse SMS d'absence tech → routé par tâche 'roster' via lib/ai.js (repli Gemini auto).
function llmRequest (messages) {
  return require('./ai').chat({ task: 'roster', messages, maxTokens: 1024, temperature: 0.1 })
}

async function parseWithLlm (text) {
  if (!cfg.AI_API_KEY && !cfg.AI_BASE_URL) return null
  try {
    const raw = await llmRequest([
      { role: 'system', content: buildSystemPrompt() },
      { role: 'user', content: text },
    ])
    // Strip markdown fences, <think> tags, extract JSON object
    let cleaned = raw.replace(/<think>[\s\S]*?<\/think>/g, '').replace(/```json\s*/g, '').replace(/```/g, '').trim()
    // Extract first JSON object if surrounded by text
    const jsonMatch = cleaned.match(/\{[\s\S]*\}/)
    if (jsonMatch) cleaned = jsonMatch[0]
    const parsed = JSON.parse(cleaned)
    if (parsed.action && ['absent', 'retour', 'none'].includes(parsed.action)) {
      log(`LLM parsed SMS: "${text}" → ${JSON.stringify(parsed)}`)
      return parsed
    }
    log(`LLM unexpected result: ${JSON.stringify(parsed)}`)
  } catch (e) {
    log(`LLM error: ${e.message}`)
  }
  return null
}

// ── Regex fallback ──

function parseWithRegex (text) {
  const normalized = text.trim().toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '')

  // Return patterns
  if (/^(retour|dispo|disponible|present|de retour|je reviens)$/i.test(normalized)) {
    return { action: 'retour' }
  }

  // Absence patterns
  const absMatch = normalized.match(/^(absent|malade|sick|formation)\s*(.*)$/i)
  if (!absMatch) return null

  const keyword = absMatch[1]
  const rest = absMatch[2].trim()
  const today = new Date()
  let from = localDateStr(today), until = null, startTime = null, endTime = null
  let reason = 'personal'

  if (keyword === 'malade' || keyword === 'sick') reason = 'medical'
  if (keyword === 'formation') reason = 'training'

  // Time range
  const timeMatch = rest.match(/(\d{1,2})[h:]?(\d{0,2})\s*[-àa]\s*(\d{1,2})[h:]?(\d{0,2})/)
  if (timeMatch) {
    startTime = timeMatch[1].padStart(2, '0') + ':' + (timeMatch[2] || '00').padStart(2, '0')
    endTime = timeMatch[3].padStart(2, '0') + ':' + (timeMatch[4] || '00').padStart(2, '0')
  }

  const dateRest = rest.replace(/(\d{1,2})[h:]?\d{0,2}\s*[-àa]\s*\d{1,2}[h:]?\d{0,2}/, '').trim()

  if (dateRest === 'demain' || dateRest === 'dem') {
    from = localDateStr(addDays(today, 1))
  } else if (dateRest.match(/^(\d+)\s*j(ours?)?$/)) {
    const n = parseInt(dateRest.match(/^(\d+)/)[1], 10)
    until = localDateStr(addDays(today, n - 1))
  } else {
    for (const [name, dayNum] of Object.entries(DAY_NAMES)) {
      if (dateRest === name) { from = localDateStr(nextWeekday(dayNum)); break }
    }
  }

  return { action: 'absent', from, until: until || from, startTime, endTime, reason, fullDay: !startTime }
}

// ── Main handler ──

async function handleAbsenceSms (from, text) {
  // First: is this from a known tech?
  const tech = await lookupTechByPhone(from)
  if (!tech) return false

  // Try LLM first (Gemini Flash), fallback to regex
  let parsed = await parseWithLlm(text)
  if (!parsed) {
    parsed = parseWithRegex(text)
    if (parsed) log(`Regex fallback parsed: "${text}" → ${JSON.stringify(parsed)}`)
  }

  if (!parsed || parsed.action === 'none') return false

  if (parsed.action === 'retour') {
    const ok = await clearTechAbsence(tech.name)
    if (ok) await sendSmsInternal(from, `✅ ${tech.full_name}, ton statut est remis à Disponible. Bonne journée!`)
    return true
  }

  if (parsed.action === 'absent') {
    const fromDate = parsed.from || localDateStr(new Date())
    const untilDate = parsed.until || fromDate
    const ok = await setTechAbsence(tech.name, {
      from: fromDate, until: untilDate,
      startTime: parsed.startTime || null, endTime: parsed.endTime || null,
      reason: parsed.reason || 'personal',
    })
    if (ok) {
      let msg = `✅ ${tech.full_name}, absence enregistrée pour le ${fromDate}`
      if (untilDate !== fromDate) msg = `✅ ${tech.full_name}, absence enregistrée du ${fromDate} au ${untilDate}`
      if (parsed.startTime && parsed.endTime) msg += ` de ${parsed.startTime} à ${parsed.endTime}`
      msg += `. Écris "retour" quand tu es disponible.`
      await sendSmsInternal(from, msg)
    }
    return true
  }

  return false
}

module.exports = { handleAbsenceSms, parseWithLlm, parseWithRegex, lookupTechByPhone }
