// Pont Chatwoot ↔ TARGO (émulation des features « entreprise » par NOTRE stack).
//   GET  /chatwoot/panel                  → fiche client ERPNext 360 (Dashboard App iframe)
//   GET  /chatwoot/lookup?email&phone&key  → JSON fiche (clé CHATWOOT_PANEL_KEY ; PII)
//   POST /chatwoot/bot?key                 → webhook Agent Bot : (1) miroir ERPNext (timeline),
//                                            (2) « Captain » émulé = Gemini rédige une réponse →
//                                            NOTE PRIVÉE (l'IA propose, l'humain dispose).
//   POST /chatwoot/sla-scan?key            → déclenche un scan SLA (aussi en cron, opt-in).
const https = require('https')
const fs = require('fs')
const nodePath = require('path')
const { json, cors, log, parseBody, lookupCustomersByEmail, lookupCustomersByPhone, createCommunication } = require('./helpers')
const payments = require('./payments')

const KEY = process.env.CHATWOOT_PANEL_KEY || ''
const BOT_KEY = process.env.CHATWOOT_BOT_KEY || ''
const CW_BASE = process.env.CHATWOOT_BASE_URL || 'https://chatwoot.gigafibre.ca'
const CW_ACCOUNT = process.env.CHATWOOT_ACCOUNT_ID || '1'
const CW_BOT_TOKEN = process.env.CHATWOOT_BOT_TOKEN || ''
const CW_AGENT_TOKEN = process.env.CHATWOOT_AGENT_TOKEN || ''
const OPS_BASE = process.env.OPS_BASE_URL || 'https://erp.gigafibre.ca/ops'

// Cibles SLA de PREMIÈRE RÉPONSE (minutes) par priorité Chatwoot — alignées sur lib/sla DEFAULTS.
let SLA_RESPONSE = { urgent: 30, high: 60, medium: 240, low: 480, none: 480 }
try { if (process.env.CHATWOOT_SLA_RESPONSE) SLA_RESPONSE = Object.assign(SLA_RESPONSE, JSON.parse(process.env.CHATWOOT_SLA_RESPONSE)) } catch (e) { /* défauts */ }

let PANEL_HTML = null
function panelHtml () {
  if (PANEL_HTML == null) {
    try { PANEL_HTML = fs.readFileSync(nodePath.join(__dirname, 'chatwoot-panel.html'), 'utf8') } catch (e) { PANEL_HTML = '<!doctype html><meta charset="utf-8"><p>Panel indisponible</p>' }
  }
  return PANEL_HTML
}

// Résout une fiche ERPNext depuis courriel (prioritaire) ou téléphone, + solde/factures.
async function lookup (email, phone) {
  let matches = []
  if (email) matches = await lookupCustomersByEmail(email, 6)
  if (!matches.length && phone) matches = await lookupCustomersByPhone(phone, 6)
  if (!matches.length) return { found: false, candidates: [], query: { email, phone } }
  const top = matches[0]
  let balance = 0
  let invoices = []
  try {
    const r = await payments.getCustomerBalance(top.name)
    balance = r.balance
    invoices = (r.invoices || []).slice(0, 8)
  } catch (e) { /* solde best-effort */ }
  const opsUrl = n => OPS_BASE + '/#/clients/' + encodeURIComponent(n)
  return {
    found: true,
    customer: { name: top.name, customer_name: top.customer_name || top.name, territory: top.territory || '', email: top.email || email || '', phone: top.phone || phone || '' },
    balance,
    invoices,
    candidates: matches.slice(1).map(m => ({ name: m.name, customer_name: m.customer_name || m.name, opsUrl: opsUrl(m.name) })),
    opsUrl: opsUrl(top.name)
  }
}

// Appel API Chatwoot avec un jeton donné (bot pour le copilote ; agent pour le scan SLA).
function cwReq (method, apiPath, bodyObj, token) {
  return new Promise((resolve, reject) => {
    const u = new URL(CW_BASE + apiPath)
    const data = bodyObj ? JSON.stringify(bodyObj) : null
    const headers = { 'Content-Type': 'application/json', api_access_token: token || '' }
    if (data) headers['Content-Length'] = Buffer.byteLength(data)
    const req = https.request({ hostname: u.hostname, port: 443, path: u.pathname + u.search, method, headers }, r => {
      let b = ''
      r.on('data', c => { b += c })
      r.on('end', () => resolve({ status: r.statusCode, body: b }))
    })
    req.on('error', reject)
    req.setTimeout(15000, () => req.destroy(new Error('chatwoot api timeout')))
    if (data) req.write(data)
    req.end()
  })
}
const chatwootApi = (m, p, b) => cwReq(m, p, b, CW_BOT_TOKEN)
const cwAgentApi = (m, p, b) => cwReq(m, p, b, CW_AGENT_TOKEN)

const isIncoming = m => m === 'incoming' || m === 0

// Miroir d'un message Chatwoot → ERPNext (Communication liée au Customer) = timeline fiche OPS.
async function mirrorToErp (ev, fiche, conv) {
  if (!fiche || !fiche.found) { log('chatwoot mirror: pas de fiche liée'); return }
  const incoming = isIncoming(ev.message_type)
  const convId = conv.id || conv.display_id || ev.conversation_id
  const convUrl = `${CW_BASE}/app/accounts/${CW_ACCOUNT}/conversations/${convId}`
  const r = await createCommunication({
    communication_type: 'Communication',
    communication_medium: 'Chat',
    subject: 'Chatwoot — ' + (fiche.customer.customer_name || ''),
    content: (incoming ? 'Client : ' : 'Agent : ') + String(ev.content || '').slice(0, 4000) + '\n\n[Chatwoot] ' + convUrl,
    sent_or_received: incoming ? 'Received' : 'Sent',
    reference_doctype: 'Customer',
    reference_name: fiche.customer.name,
    status: 'Linked'
  })
  log('chatwoot mirror: Communication HTTP ' + (r && r.status) + ' → ' + fiche.customer.name)
}

// Traite un évènement Agent Bot : (1) miroir ERPNext, (2) suggestion IA en note privée (message client).
async function processBotEvent (ev) {
  if (!ev || ev.event !== 'message_created') return
  if (ev.private) return // jamais les notes internes (ni copilote, ni mirror → pas de boucle)
  const conv = ev.conversation || {}
  const convId = conv.id || ev.conversation_id
  if (!convId) return
  const sender = (conv.meta && conv.meta.sender) || ev.sender || {}
  let fiche = null
  try { fiche = await lookup(sender.email || '', sender.phone_number || '') } catch (e) { /* best-effort */ }

  // (1) Miroir timeline ERPNext — entrant + sortant public
  mirrorToErp(ev, fiche, conv).catch(e => log('chatwoot mirror: ' + (e && e.message)))

  // (2) Copilote IA — uniquement sur un message CLIENT (entrant)
  if (!isIncoming(ev.message_type)) return
  const ficheTxt = (fiche && fiche.found)
    ? `Fiche client : ${fiche.customer.customer_name} · ${fiche.customer.territory || '—'} · solde ${fiche.balance} $ · ${fiche.invoices.length} facture(s) impayée(s).`
    : 'Aucune fiche client liée (nouveau contact).'
  const recent = (conv.messages || []).slice(-8)
    .map(m => (isIncoming(m.message_type) ? 'Client : ' : 'Agent : ') + String(m.content || '').slice(0, 500))
    .join('\n')
  const lastText = ev.content || ''
  const sys = "Tu es un agent du support technique d'un fournisseur Internet résidentiel (TARGO / Gigafibre). " +
    "Rédige une RÉPONSE COURTE, polie et CONCRÈTE en français, à proposer à l'agent humain qui la validera avant envoi. " +
    'Utilise le contexte client si pertinent (solde, factures). Va droit au but, pas de longues salutations. ' +
    "Ne promets rien d'irréversible (remboursement, crédit, rendez-vous ferme) — propose plutôt de vérifier."
  const userMsg = ficheTxt + '\n\nFil récent :\n' + (recent || ('Client : ' + lastText)) + '\n\nDernier message du client : ' + lastText + '\n\nRéponse suggérée :'
  let reply = ''
  try {
    reply = await require('./ai').chat({ task: 'copilot', maxTokens: 400, temperature: 0.3, messages: [{ role: 'system', content: sys }, { role: 'user', content: userMsg }] })
  } catch (e) { log('chatwoot copilot AI: ' + e.message); return }
  if (!reply || !reply.trim()) return
  const note = '💡 Réponse suggérée (IA) :\n\n' + reply.trim() + "\n\n— Copilote TARGO · à vérifier avant d'envoyer"
  try {
    const r = await chatwootApi('POST', `/api/v1/accounts/${CW_ACCOUNT}/conversations/${convId}/messages`, { content: note, private: true })
    log(`chatwoot copilot: note conv=${convId} status=${r.status}`)
  } catch (e) { log('chatwoot copilot post: ' + e.message) }
}

async function handleBot (req, res, url) {
  const key = url.searchParams.get('key') || ''
  if (!BOT_KEY || key !== BOT_KEY) return json(res, 401, { error: 'unauthorized' })
  let ev = {}
  try { ev = await parseBody(req) } catch (e) { return json(res, 400, { error: 'bad body' }) }
  json(res, 200, { ok: true }) // ACK rapide ; traitement en arrière-plan
  processBotEvent(ev).catch(e => log('chatwoot bot: ' + (e && e.message)))
}

// Émulation EE « SLA » : convs ouvertes SANS 1re réponse au-delà de la cible (par priorité)
// → étiquette « sla-en-retard » + note privée. Idempotent (skip si déjà étiqueté). Jeton AGENT.
async function slaScan () {
  if (!CW_AGENT_TOKEN) return { scanned: 0, flagged: 0, skipped: 'no_agent_token' }
  const r = await cwAgentApi('GET', `/api/v1/accounts/${CW_ACCOUNT}/conversations?status=open`)
  if (r.status !== 200) { log('chatwoot sla: list HTTP ' + r.status); return { scanned: 0, flagged: 0, error: r.status } }
  let payload = []
  try { payload = JSON.parse(r.body).data.payload || [] } catch (e) { return { scanned: 0, flagged: 0, error: 'parse' } }
  const nowS = Math.floor(Date.now() / 1000)
  let flagged = 0
  for (const c of payload) {
    if (c.first_reply_created_at) continue // déjà répondu → SLA réponse respecté
    const since = c.waiting_since || c.created_at || nowS
    const mins = Math.round((nowS - since) / 60)
    const prio = c.priority || 'none'
    const target = SLA_RESPONSE[prio] != null ? SLA_RESPONSE[prio] : SLA_RESPONSE.none
    if (mins < target) continue
    let cur = []
    try { const lr = await cwAgentApi('GET', `/api/v1/accounts/${CW_ACCOUNT}/conversations/${c.id}/labels`); cur = JSON.parse(lr.body).payload || [] } catch (e) { /* */ }
    if (cur.includes('sla-en-retard')) continue // déjà signalé
    await cwAgentApi('POST', `/api/v1/accounts/${CW_ACCOUNT}/conversations/${c.id}/labels`, { labels: cur.concat(['sla-en-retard']) })
    await cwAgentApi('POST', `/api/v1/accounts/${CW_ACCOUNT}/conversations/${c.id}/messages`, { content: `⏰ SLA réponse dépassé — ${mins} min sans réponse (cible ${target} min, priorité ${prio}). À prendre en charge en priorité.`, private: true })
    flagged++
  }
  if (flagged) log('chatwoot sla: ' + flagged + ' conv(s) en retard signalée(s)')
  return { scanned: payload.length, flagged }
}

function startSlaScan () {
  if (process.env.CHATWOOT_SLA_SCAN !== 'on') return
  log('chatwoot sla: scan activé (toutes les 5 min)')
  setTimeout(() => slaScan().catch(e => log('chatwoot sla: ' + (e && e.message))), 20000)
  setInterval(() => slaScan().catch(e => log('chatwoot sla: ' + (e && e.message))), 5 * 60 * 1000)
}

async function handle (req, res, method, path, url) {
  cors(res, 'GET, POST, OPTIONS')
  if (method === 'OPTIONS') { res.writeHead(204); return res.end() }

  if (path === '/chatwoot/panel') {
    res.writeHead(200, {
      'Content-Type': 'text/html; charset=utf-8',
      'Cache-Control': 'no-cache',
      'Content-Security-Policy': 'frame-ancestors https://chatwoot.gigafibre.ca'
    })
    return res.end(panelHtml())
  }

  if (path === '/chatwoot/lookup') {
    const key = url.searchParams.get('key') || ''
    if (!KEY || key !== KEY) return json(res, 401, { error: 'unauthorized' })
    const email = (url.searchParams.get('email') || '').trim()
    const phone = (url.searchParams.get('phone') || '').trim()
    if (!email && !phone) return json(res, 200, { found: false, candidates: [], query: {} })
    try { return json(res, 200, await lookup(email, phone)) } catch (e) { return json(res, 500, { error: e.message }) }
  }

  if (path === '/chatwoot/bot' && method === 'POST') return handleBot(req, res, url)

  if (path === '/chatwoot/sla-scan' && method === 'POST') {
    if (!BOT_KEY || (url.searchParams.get('key') || '') !== BOT_KEY) return json(res, 401, { error: 'unauthorized' })
    try { return json(res, 200, await slaScan()) } catch (e) { return json(res, 500, { error: e.message }) }
  }

  return json(res, 404, { error: 'not found' })
}

module.exports = { handle, startSlaScan }
