'use strict'
// Referral Credit — validation + application endpoints backing the wizard's
// referral code field. Codes are stored in the ERPNext "Referral Credit"
// doctype (code unique, status Active/Used/Fulfilled/Cancelled).
//
//   POST /api/referral/validate  { code }  → { ok, referrer, error? }
//   POST /api/referral/apply     { code, quotation, customer } → { ok, error? }
//   POST /api/referral/generate  { customer }                   → { ok, code }
//
// Apply is called from the Vue wizard at publish time (after quote creation)
// so the code flips to "Used" and links to the quotation. Fulfilled happens
// server-side once the service invoice is submitted (not here).

const { log, json, parseBody } = require('./helpers')
const erp = require('./erp')

const DT = 'Referral Credit'

async function fetchByCode (code) {
  const rows = await erp.list(DT, {
    filters: [['code', '=', code]],
    fields: ['name', 'code', 'referrer', 'referrer_customer_name', 'status', 'new_subscriber_credit', 'referrer_credit'],
    limit: 1,
  })
  return rows[0] || null
}

async function validateCode (code) {
  if (!code || !code.trim()) return { ok: false, error: 'Code manquant' }
  const normalized = code.trim().toUpperCase()
  const row = await fetchByCode(normalized)
  if (!row) return { ok: false, error: 'Code introuvable' }
  if (row.status !== 'Active') {
    return { ok: false, error: `Code déjà ${row.status === 'Used' ? 'utilisé' : row.status === 'Fulfilled' ? 'complété' : 'annulé'}` }
  }
  return {
    ok: true,
    code: row.code,
    referrer: row.referrer,
    referrer_name: row.referrer_customer_name || '',
    new_subscriber_credit: Number(row.new_subscriber_credit) || 50,
    referrer_credit: Number(row.referrer_credit) || 50,
  }
}

async function applyCode (code, quotation, customer) {
  if (!code) return { ok: false, error: 'Code manquant' }
  const normalized = String(code).trim().toUpperCase()
  const row = await fetchByCode(normalized)
  if (!row) return { ok: false, error: 'Code introuvable' }
  if (row.status !== 'Active') return { ok: false, error: `Code non applicable (statut: ${row.status})` }
  if (row.referrer === customer) return { ok: false, error: "On ne peut pas utiliser son propre code" }

  const patch = {
    status: 'Used',
    applied_on: new Date().toISOString().slice(0, 10),
  }
  if (quotation) patch.referred_quotation = quotation
  if (customer) patch.referred_customer = customer
  const res = await erp.update(DT, row.name, patch)
  if (!res.ok) {
    log('referral.apply PUT failed:', res.status, res.error)
    return { ok: false, error: 'Erreur de mise à jour (' + (res.status || 'err') + ')' }
  }
  return { ok: true, code: row.code }
}

// Generate a new code for a customer. Idempotent — returns the existing
// Active code if one already exists for that referrer (customers can share
// one code perpetually until explicitly cancelled).
async function generateCode (customer) {
  if (!customer) return { ok: false, error: 'customer manquant' }
  const existing = await erp.list(DT, {
    filters: [['referrer', '=', customer], ['status', '=', 'Active']],
    fields: ['name', 'code'],
    limit: 1,
  })
  if (existing.length) {
    return { ok: true, code: existing[0].code, created: false }
  }
  // New code — 6 uppercase alphanumerics, prefixed with GIGA-. Retry on
  // collision (the unique constraint guarantees we don't double-insert).
  const alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789' // ambiguous chars omitted
  for (let attempt = 0; attempt < 8; attempt++) {
    let suffix = ''
    for (let i = 0; i < 6; i++) suffix += alphabet[Math.floor(Math.random() * alphabet.length)]
    const code = `GIGA-${suffix}`
    const res = await erp.create(DT, { code, referrer: customer, status: 'Active' })
    if (res.ok) return { ok: true, code, created: true }
    // 409/417 on duplicate code or field rejection — retry with new suffix
    if (res.status !== 409 && res.status !== 417) {
      log('referral.generate POST failed:', res.status, res.error)
      return { ok: false, error: 'Erreur ERP (' + (res.status || 'err') + ')' }
    }
  }
  return { ok: false, error: 'Génération échouée après 8 tentatives' }
}

async function handle (req, res, method, path) {
  if (path === '/api/referral/validate' && method === 'POST') {
    try {
      const body = await parseBody(req)
      const result = await validateCode(body.code || '')
      return json(res, 200, result)
    } catch (e) {
      log('referral.validate error:', e.message)
      return json(res, 500, { ok: false, error: e.message })
    }
  }

  if (path === '/api/referral/apply' && method === 'POST') {
    try {
      const body = await parseBody(req)
      const result = await applyCode(body.code || '', body.quotation || '', body.customer || '')
      return json(res, result.ok ? 200 : 400, result)
    } catch (e) {
      log('referral.apply error:', e.message)
      return json(res, 500, { ok: false, error: e.message })
    }
  }

  if (path === '/api/referral/generate' && method === 'POST') {
    try {
      const body = await parseBody(req)
      const result = await generateCode(body.customer || '')
      return json(res, result.ok ? 200 : 400, result)
    } catch (e) {
      log('referral.generate error:', e.message)
      return json(res, 500, { ok: false, error: e.message })
    }
  }

  return json(res, 404, { error: 'Referral route not found: ' + path })
}

module.exports = { handle, validateCode, applyCode, generateCode }
