'use strict'
const { log, json, parseBody, erpFetch } = require('./helpers')
const { searchAddresses } = require('./address-search')
const { sendOTP, verifyOTP } = require('./otp')
const { getTemplateSteps } = require('./project-templates')
const { orderConfirmationHtml } = require('./email-templates')

function erpQuery (doctype, filters, fields, limit, orderBy) {
  let url = `/api/resource/${encodeURIComponent(doctype)}?filters=${encodeURIComponent(JSON.stringify(filters))}&fields=${encodeURIComponent(JSON.stringify(fields))}`
  if (orderBy) url += `&order_by=${encodeURIComponent(orderBy)}`
  if (limit) url += `&limit_page_length=${limit}`
  return erpFetch(url)
}

async function getCatalog () {
  const fields = [
    'name', 'item_code', 'item_name', 'item_group', 'standard_rate',
    'description', 'image',
    'project_template_id', 'requires_visit', 'delivery_method',
    'is_bundle_parent', 'billing_type', 'service_category',
  ]
  const res = await erpQuery('Item', [['is_sales_item', '=', 1], ['disabled', '=', 0]], fields, 100, 'service_category,standard_rate')

  if (res.status !== 200) {
    log('Catalog fetch failed:', res.status)
    return []
  }

  return (res.data.data || []).map(item => ({
    item_code: item.item_code,
    item_name: item.item_name,
    item_group: item.item_group,
    rate: item.standard_rate || 0,
    description: item.description || '',
    image: item.image || '',
    project_template_id: item.project_template_id || '',
    requires_visit: !!item.requires_visit,
    delivery_method: item.delivery_method || '',
    is_bundle: !!item.is_bundle_parent,
    billing_type: item.billing_type || '',
    service_category: item.service_category || '',
  }))
}

async function processCheckout (body) {
  const { contact = {}, installation = {} } = body
  const items = body.items || []
  const customer_name = body.customer_name || contact.name || ''
  const phone = body.phone || contact.phone || ''
  const email = body.email || contact.email || ''
  const address = body.address || contact.address || ''
  const city = body.city || contact.city || ''
  const postal_code = body.postal_code || contact.postal_code || ''
  const preferred_date = body.preferred_date || installation.preferred_date || ''
  const preferred_slot = body.preferred_slot || installation.preferred_slot || ''
  const notes = body.notes || ''
  const mode = body.mode || 'postpaid'

  log('Checkout request:', { customer_name, phone, email, items: items.length, mode })

  if (!items?.length) throw new Error('Aucun article dans le panier')
  if (!customer_name) throw new Error('Nom du client requis')
  if (!phone && !email) throw new Error('Téléphone ou courriel requis')

  const today = new Date().toISOString().split('T')[0]
  const result = { ok: true, items_count: items.length }

  let customerName = ''
  const providedCustomerId = body.customer_id || ''
  try {
    if (providedCustomerId) {
      customerName = providedCustomerId
      result.customer_existing = true
      log('Using OTP-verified customer:', customerName)
    }
    const { lookupCustomerByPhone } = require('./helpers')
    if (!customerName && phone) {
      const existing = await lookupCustomerByPhone(phone)
      if (existing) {
        customerName = existing.name
        result.customer_existing = true
      }
    }
    if (!customerName) {
      const custPayload = {
        customer_name,
        customer_type: 'Individual',
        customer_group: 'Individual',
        territory: 'Canada',
        cell_phone: phone || '',
        email_id: email || '',
      }
      log('Creating customer:', custPayload)
      const custRes = await erpFetch('/api/resource/Customer', { method: 'POST', body: custPayload })
      log('Customer creation result:', custRes.status, custRes.data?.data?.name || JSON.stringify(custRes.data).substring(0, 200))
      if (custRes.status === 200 && custRes.data?.data) {
        customerName = custRes.data.data.name
        result.customer_created = true
      } else {
        customerName = customer_name
      }
    }
  } catch (e) {
    log('Customer lookup/create failed:', e.message)
    customerName = customer_name
  }

  const recurringItems = items.filter(i => i.billing_type === 'Mensuel' || i.billing_type === 'Annuel')
  const allItems = items.map(i => ({
    item_code: i.item_code,
    item_name: i.item_name,
    qty: i.qty || 1,
    rate: i.rate,
    description: i.billing_type === 'Mensuel'
      ? `${i.item_name} — ${i.rate}$/mois`
      : i.billing_type === 'Annuel'
        ? `${i.item_name} — ${i.rate}$/an`
        : i.item_name,
  }))

  let orderName = ''
  try {
    const soPayload = {
      customer: customerName,
      company: 'TARGO',
      currency: 'CAD',
      selling_price_list: 'Standard Selling',
      transaction_date: today,
      delivery_date: preferred_date || today,
      items: allItems,
      terms: notes || '',
    }
    const soRes = await erpFetch('/api/resource/Sales%20Order', { method: 'POST', body: JSON.stringify(soPayload) })
    if (soRes.status === 200 && soRes.data?.data) {
      orderName = soRes.data.data.name
      result.sales_order = orderName
      log(`Sales Order created: ${orderName} for ${customerName}`)
    } else {
      log('Sales Order creation failed:', soRes.status, JSON.stringify(soRes.data).substring(0, 300))
      result.sales_order_error = `ERPNext ${soRes.status}`
    }
  } catch (e) {
    log('Sales Order creation failed:', e.message)
    result.sales_order_error = e.message
  }

  for (const item of recurringItems) {
    try {
      let planName = null
      try {
        const findRes = await erpFetch(`/api/resource/Subscription%20Plan/${encodeURIComponent(item.item_code)}`)
        if (findRes.status === 200) planName = findRes.data?.data?.name
      } catch {}

      if (!planName) {
        const planRes = await erpFetch('/api/resource/Subscription%20Plan', {
          method: 'POST',
          body: JSON.stringify({
            plan_name: item.item_code,
            item: item.item_code,
            currency: 'CAD',
            price_determination: 'Fixed Rate',
            cost: item.rate,
            billing_interval: item.billing_type === 'Annuel' ? 'Year' : 'Month',
            billing_interval_count: 1,
          }),
        })
        if (planRes.status === 200) planName = planRes.data?.data?.name
      }

      if (planName) {
        await erpFetch('/api/resource/Subscription', {
          method: 'POST',
          body: JSON.stringify({
            party_type: 'Customer',
            party: customerName,
            company: 'TARGO',
            start_date: today,
            generate_invoice_at: 'Beginning of the current subscription period',
            days_until_due: 30,
            follow_calendar_months: 1,
            plans: [{ plan: planName, qty: item.qty || 1 }],
          }),
        })
        log(`Subscription created for ${item.item_code}`)
      }
    } catch (e) {
      log(`Subscription failed for ${item.item_code}:`, e.message)
    }
  }

  const templatesNeeded = new Set()
  for (const item of items) {
    if (item.project_template_id) templatesNeeded.add(item.project_template_id)
  }
  log('Templates needed:', [...templatesNeeded], 'from items:', items.map(i => `${i.item_code}:${i.project_template_id || 'none'}`))

  const createdJobs = []
  if (templatesNeeded.size > 0) {
    const fullAddress = [address, city, postal_code].filter(Boolean).join(', ')

    for (const templateId of templatesNeeded) {
      const steps = getTemplateSteps(templateId)
      if (!steps.length) continue
      const ref = await require('./dispatch').nextJobRef() // numéro standardisé YYYYMMDD-XXX (remplace DJ-<base36>)

      for (let i = 0; i < steps.length; i++) {
        const step = steps[i]
        const ticketId = `${ref}-s${i + 1}`

        let dependsOn = ''
        if (step.depends_on_step != null) {
          const depJob = createdJobs[step.depends_on_step]
          if (depJob) dependsOn = depJob.name
        }
        const parentJob = createdJobs.length > 0 ? createdJobs[0].name : ''

        // Chain gating — root job "open", dependents "On Hold" until parent
        // completes (see dispatch.unblockDependents).
        const jobPayload = {
          ticket_id: ticketId,
          subject: step.subject,
          address: fullAddress,
          duration_h: step.duration_h || 1,
          priority: step.priority || 'medium',
          status: dependsOn ? 'On Hold' : 'open',
          job_type: step.job_type || 'Autre',
          customer: customerName,
          sales_order: orderName || '',
          order_source: 'Online',
          depends_on: dependsOn,
          parent_job: parentJob,
          step_order: i + 1,
          on_open_webhook: step.on_open_webhook || '',
          on_close_webhook: step.on_close_webhook || '',
          notes: [
            step.assigned_group ? `Groupe: ${step.assigned_group}` : '',
            orderName ? `Sales Order: ${orderName}` : '',
            preferred_date ? `Date souhaitée: ${preferred_date} ${preferred_slot || ''}` : '',
            'Commande en ligne',
          ].filter(Boolean).join(' | '),
          scheduled_date: preferred_date || '',
        }

        try {
          const jobRes = await erpFetch('/api/resource/Dispatch%20Job', { method: 'POST', body: JSON.stringify(jobPayload) })
          if (jobRes.status === 200 && jobRes.data?.data) {
            createdJobs.push(jobRes.data.data)
          }
        } catch (e) {
          log(`Job creation failed: ${step.subject} — ${e.message}`)
        }
      }
    }
    result.jobs_created = createdJobs.length
  }

  if (phone) {
    try {
      const { sendSmsInternal } = require('./twilio')
      const itemList = items.map(i => `• ${i.item_name}`).join('\n')
      const msg = `Gigafibre — Commande confirmée!\n\n${itemList}\n\n${orderName ? `Réf: ${orderName}\n` : ''}${preferred_date ? `Date souhaitée: ${preferred_date}\n` : ''}Nous vous contacterons pour confirmer les détails.\n\nMerci!`
      await sendSmsInternal(phone, msg)
      result.sms_sent = true
    } catch (e) {
      log('Checkout confirmation SMS failed:', e.message)
    }
  }

  if (email) {
    try {
      const { sendEmail } = require('./email')
      const itemRows = items.map(i =>
        `<tr><td style="padding:8px 12px;border-bottom:1px solid #e2e8f0">${i.item_name}</td><td style="padding:8px 12px;border-bottom:1px solid #e2e8f0;text-align:right">${i.rate.toFixed(2)}$${i.billing_type === 'Mensuel' ? '/mois' : i.billing_type === 'Annuel' ? '/an' : ''}</td></tr>`
      ).join('')

      await sendEmail({
        to: email,
        subject: `Confirmation de commande${orderName ? ` ${orderName}` : ''} — Gigafibre`,
        html: orderConfirmationHtml({ orderName, customer_name, itemRows, preferred_date, preferred_slot }),
      })
      result.email_sent = true
    } catch (e) {
      log('Checkout confirmation email failed:', e.message)
    }
  }

  result.order_id = orderName || ('CMD-' + Date.now().toString(36).toUpperCase())
  return result
}

async function handle (req, res, method, path) {
  if (path === '/api/catalog' && method === 'GET') {
    try {
      const catalog = await getCatalog()
      return json(res, 200, { ok: true, items: catalog })
    } catch (e) {
      log('Catalog error:', e.message)
      return json(res, 500, { error: 'Failed to load catalog' })
    }
  }

  if (path === '/api/checkout' && method === 'POST') {
    try {
      const body = await parseBody(req)
      const result = await processCheckout(body)
      return json(res, 200, result)
    } catch (e) {
      log('Checkout error:', e.message)
      return json(res, 400, { ok: false, error: e.message })
    }
  }

  if (path === '/api/orders' && method === 'GET') {
    try {
      const { URL } = require('url')
      const url = new URL(req.url, 'http://localhost')
      const limit = parseInt(url.searchParams.get('limit') || '20', 10)
      const customer = url.searchParams.get('customer') || ''
      const fields = ['name', 'customer', 'customer_name', 'transaction_date', 'grand_total', 'status', 'creation']
      let filters = [['docstatus', '=', 0]]
      if (customer) filters.push(['customer', '=', customer])
      const soRes = await erpQuery('Sales Order', filters, fields, limit, 'creation desc')
      return json(res, 200, { ok: true, orders: soRes.data?.data || [] })
    } catch (e) {
      log('Orders list error:', e.message)
      return json(res, 500, { error: e.message })
    }
  }

  if (path.startsWith('/api/order/') && method === 'GET') {
    try {
      const orderName = decodeURIComponent(path.replace('/api/order/', ''))
      const soRes = await erpFetch(`/api/resource/Sales%20Order/${encodeURIComponent(orderName)}`)
      if (soRes.status !== 200) return json(res, 404, { error: 'Commande non trouvée' })
      return json(res, 200, { ok: true, order: soRes.data?.data })
    } catch (e) {
      return json(res, 500, { error: e.message })
    }
  }

  if (path === '/api/address-search' && method === 'POST') {
    try {
      const body = await parseBody(req)
      if (!body.q || body.q.length < 3) return json(res, 200, { results: [] })
      const results = await searchAddresses(body.q, body.limit || 8)
      return json(res, 200, { results })
    } catch (e) {
      log('Address search error:', e.message)
      return json(res, 500, { error: 'Address search failed' })
    }
  }

  if (path === '/api/otp/send' && method === 'POST') {
    try {
      const body = await parseBody(req)
      if (!body.identifier) return json(res, 400, { error: 'Email ou téléphone requis' })
      const result = await sendOTP(body.identifier)
      return json(res, 200, result)
    } catch (e) {
      log('OTP send error:', e.message)
      return json(res, 500, { error: e.message })
    }
  }

  if (path === '/api/otp/verify' && method === 'POST') {
    try {
      const body = await parseBody(req)
      if (!body.identifier || !body.code) return json(res, 400, { error: 'identifier et code requis' })
      const result = await verifyOTP(body.identifier, body.code)
      return json(res, 200, result)
    } catch (e) {
      return json(res, 500, { error: e.message })
    }
  }

  if (path === '/api/accept-for-client' && method === 'POST') {
    try {
      const body = await parseBody(req)
      const { quotation, agent_name } = body
      if (!quotation) return json(res, 400, { error: 'quotation required' })

      const acceptance = require('./acceptance')
      const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress || ''
      await acceptance.acceptQuotation(quotation, {
        method: 'Accepté par agent',
        contact: agent_name || req.headers['x-authentik-email'] || 'Agent',
        ip,
        userAgent: req.headers['user-agent'] || '',
      })

      return json(res, 200, { ok: true, quotation, message: 'Devis accepté. Tâches créées.' })
    } catch (e) {
      log('Accept-for-client error:', e.message)
      return json(res, 500, { error: e.message })
    }
  }

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

module.exports = { handle, getCatalog, processCheckout, getTemplateSteps }
