/**
 * Composable for subscription management actions.
 * Handles status toggling, frequency changes, recurring settings, drag reorder, and field saves.
 */
import { ref } from 'vue'
import { Notify } from 'quasar'
import { authFetch } from 'src/api/auth'
import { BASE_URL } from 'src/config/erpnext'
import { formatMoney } from 'src/composables/useFormatters'

// Frappe REST update — always targets Service Subscription now. Stock
// ERPNext Subscription rows are legacy-migration artefacts that we no
// longer display or mutate from ops; see useClientData.loadSubscriptions.
async function updateSub (name, fields) {
  // Map normalized UI field names → Service Subscription fields.
  const mapped = {}
  for (const [k, v] of Object.entries(fields)) {
    if (k === 'actual_price') mapped.monthly_price = v
    else if (k === 'custom_description') mapped.plan_name = v
    else if (k === 'billing_frequency') mapped.billing_cycle = v === 'A' ? 'Annuel' : 'Mensuel'
    else if (k === 'status') {
      mapped.status = v === 'Active' ? 'Actif'
                    : v === 'Cancelled' ? 'Annulé'
                    : v === 'Suspended' ? 'Suspendu'
                    : v === 'Pending' ? 'En attente'
                    : v
    }
    else if (k === 'cancelation_date') mapped.cancellation_date = v
    else if (k === 'cancel_at_period_end') { /* Service Subscription uses end_date + status for lifecycle */ }
    else mapped[k] = v
  }

  const res = await authFetch(BASE_URL + '/api/resource/Service%20Subscription/' + encodeURIComponent(name), {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(mapped),
  })
  if (!res.ok) {
    // Try to surface the ERPNext exception one-liner instead of raw HTML.
    let msg = 'Update failed: ' + res.status
    try {
      const body = await res.json()
      msg = body?.exception?.split('\n')[0] || body?._server_messages || msg
    } catch {}
    throw new Error(msg)
  }
  return res.json()
}

/**
 * @param {import('vue').Ref<Array>} subscriptions - Reactive subscriptions list
 * @param {import('vue').Ref<Object>} customer - Reactive customer object
 * @param {import('vue').Ref<Array>} comments - Reactive comments list
 * @param {Function} invalidateCache - Cache invalidation from useSubscriptionGroups
 */
export function useSubscriptionActions (subscriptions, customer, comments, invalidateCache) {
  const subSaving = ref(null)
  const togglingRecurring = ref(null)

  // Log a subscription change as a Comment on the Customer for audit trail
  async function logSubChange (sub, message) {
    try {
      const label = sub.custom_description || sub.item_name || sub.item_code || sub.name
      const body = {
        doctype: 'Comment', comment_type: 'Comment',
        reference_doctype: 'Customer', reference_name: customer.value.name,
        content: `[${sub.name}] ${label} — ${message}`,
      }
      const res = await authFetch(BASE_URL + '/api/resource/Comment', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      })
      if (res.ok) {
        const data = await res.json()
        comments.value.unshift(data.data)
      }
    } catch {}
  }

  async function toggleSubStatus (sub) {
    const action = sub.name + ':status'
    if (subSaving.value) return
    subSaving.value = action
    const newStatus = sub.status === 'Cancelled' ? 'Active' : 'Cancelled'
    const today = new Date().toISOString().slice(0, 10)
    try {
      const updates = { status: newStatus }
      if (newStatus === 'Cancelled') {
        updates.cancelation_date = today
        if (!sub.end_date) updates.end_date = sub.current_invoice_end || today
      } else {
        updates.cancelation_date = null
      }
      await updateSub(sub.name, updates)
      sub.status = newStatus
      if (updates.end_date) sub.end_date = updates.end_date
      const msg = newStatus === 'Cancelled'
        ? `Service désactivé le ${today}`
        : `Service réactivé le ${today}`
      logSubChange(sub, msg)
      if (sub.service_location) invalidateCache(sub.service_location)
      Notify.create({ type: 'positive', message: msg, timeout: 2500 })
    } catch (e) {
      Notify.create({ type: 'negative', message: 'Erreur: ' + (e.message || 'impossible de modifier le statut'), timeout: 4000 })
    } finally {
      subSaving.value = null
    }
  }

  async function toggleFrequency (sub) {
    const action = sub.name + ':freq'
    if (subSaving.value) return
    subSaving.value = action
    const oldFreq = sub.billing_frequency
    const newFreq = oldFreq === 'A' ? 'M' : 'A'
    try {
      await updateSub(sub.name, { billing_frequency: newFreq })
      const msg = newFreq === 'A'
        ? `Fréquence changée: Mensuel → Annuel`
        : `Fréquence changée: Annuel → Mensuel`
      logSubChange(sub, msg)
      if (sub.service_location) invalidateCache(sub.service_location)
      sub.billing_frequency = newFreq
    } catch {} finally {
      subSaving.value = null
    }
  }

  async function toggleRecurring (sub) {
    if (togglingRecurring.value) return
    togglingRecurring.value = sub.name
    const newVal = Number(sub.cancel_at_period_end) ? 0 : 1
    try {
      const updates = { cancel_at_period_end: newVal }
      if (newVal && !sub.end_date) updates.end_date = sub.current_invoice_end || new Date().toISOString().slice(0, 10)
      await updateSub(sub.name, updates)
      sub.cancel_at_period_end = newVal
      if (updates.end_date) sub.end_date = updates.end_date
      const msg = newVal ? 'Récurrence désactivée' : 'Récurrence activée'
      logSubChange(sub, msg)
      Notify.create({ type: 'positive', message: msg, timeout: 2500 })
    } catch {
      Notify.create({ type: 'negative', message: 'Erreur: impossible de modifier le récurrent', timeout: 3000 })
    } finally {
      togglingRecurring.value = null
    }
  }

  async function toggleRecurringModal (doc) {
    const newVal = Number(doc.cancel_at_period_end) ? 0 : 1
    try {
      const updates = { cancel_at_period_end: newVal }
      if (newVal && !doc.end_date) updates.end_date = doc.current_invoice_end || new Date().toISOString().slice(0, 10)
      await updateSub(doc.name, updates)
      doc.cancel_at_period_end = newVal
      if (updates.end_date) doc.end_date = updates.end_date
      const listSub = subscriptions.value.find(s => s.name === doc.name)
      if (listSub) {
        listSub.cancel_at_period_end = newVal
        if (updates.end_date) listSub.end_date = updates.end_date
      }
      const msg = newVal ? 'Récurrence désactivée' : 'Récurrence activée'
      logSubChange(doc, msg)
      Notify.create({ type: 'positive', message: msg, timeout: 2500 })
    } catch (e) {
      Notify.create({ type: 'negative', message: 'Erreur: ' + (e.message || 'impossible de modifier'), timeout: 3000 })
    }
  }

  async function saveSubField (doc, field) {
    try {
      const oldVal = subscriptions.value.find(s => s.name === doc.name)?.[field]
      await updateSub(doc.name, { [field]: doc[field] ?? '' })
      const listSub = subscriptions.value.find(s => s.name === doc.name)
      if (listSub) {
        listSub[field] = doc[field]
        if (listSub.service_location) invalidateCache(listSub.service_location)
      }
      const fieldLabels = { actual_price: 'Prix', custom_description: 'Description' }
      if (fieldLabels[field]) {
        const newVal = doc[field] ?? ''
        const msg = field === 'actual_price'
          ? `${fieldLabels[field]} modifié: ${formatMoney(oldVal)} → ${formatMoney(newVal)}`
          : `${fieldLabels[field]} modifié: "${oldVal || '—'}" → "${newVal || '—'}"`
        logSubChange(doc, msg)
      }
    } catch {}
  }

  // vuedraggable mutates the bound list in-place, so by the time this
  // handler fires the `items` array (passed by the template) already
  // reflects the new order. We persist display_order in 10-step increments
  // — leaves room for manual inserts (frappe Link-sort-by-number ugh) —
  // and only PUT the rows whose position actually changed to avoid
  // N writes on every drag.
  async function onSubDragChange (evt, locName, items = null) {
    // vuedraggable emits an object with {added|removed|moved}; old signature
    // (evt, locName) with no items still works for cache-only invalidation.
    if (evt.added || evt.removed || evt.moved) invalidateCache(locName)
    if (!items || !items.length) return

    const writes = []
    for (let i = 0; i < items.length; i++) {
      const want = (i + 1) * 10       // 10, 20, 30… (keeps manual gaps)
      const item = items[i]
      if (!item || item.display_order === want) continue
      item.display_order = want       // optimistic local update
      writes.push(
        authFetch(BASE_URL + '/api/resource/Service%20Subscription/' + encodeURIComponent(item.name), {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ display_order: want }),
        }).catch(() => null)
      )
    }
    if (writes.length) {
      try { await Promise.all(writes) } catch {}
    }
  }

  return {
    subSaving,
    togglingRecurring,
    toggleSubStatus,
    toggleFrequency,
    toggleRecurring,
    toggleRecurringModal,
    saveSubField,
    logSubChange,
    onSubDragChange,
  }
}
