import { ref } from 'vue'
import { listDocs, getDoc } from 'src/api/erp'
import { authFetch } from 'src/api/auth'
import { BASE_URL } from 'src/config/erpnext'
import { HUB_URL as _HUB_URL } from 'src/config/hub'

export function useClientData (deps) {
  const { equipment, modalOpen, ticketsExpanded, invoicesExpanded, paymentsExpanded, invalidateAll, fetchStatus, fetchOltStatus } = deps

  const loading = ref(true)
  const customer = ref(null)
  const contact = ref(null)
  const locations = ref([])
  const subscriptions = ref([])
  const tickets = ref([])
  const invoices = ref([])
  const payments = ref([])
  const voipLines = ref([])
  const paymentMethods = ref([])
  const arrangements = ref([])
  const quotations = ref([])
  const serviceContracts = ref([])
  const comments = ref([])
  const accountBalance = ref(null)
  const refundsByPi = ref({}) // { pi_xxx: { amount_refunded, fully_refunded, status, refunded_at } } — statut remboursement Stripe par PaymentIntent
  const stripeCharges = ref([]) // charges Stripe réelles du client (peuvent ne pas être des Payment Entry ERPNext)

  const loadingMoreTickets = ref(false)
  const loadingMoreInvoices = ref(false)
  const loadingMorePayments = ref(false)

  function resetState () {
    loading.value = true
    customer.value = null
    locations.value = []
    subscriptions.value = []
    equipment.value = []
    tickets.value = []
    invoices.value = []
    payments.value = []
    voipLines.value = []
    paymentMethods.value = []
    arrangements.value = []
    quotations.value = []
    serviceContracts.value = []
    comments.value = []
    contact.value = null
    modalOpen.value = false
    ticketsExpanded.value = false
    invoicesExpanded.value = false
    paymentsExpanded.value = false
    refundsByPi.value = {}
    stripeCharges.value = []
  }

  function loadLocations (custFilter) {
    return listDocs('Service Location', {
      filters: custFilter,
      fields: ['name', 'location_name', 'status', 'address_line', 'city', 'postal_code',
        'connection_type', 'olt_port', 'network_id', 'contact_name', 'contact_phone',
        'longitude', 'latitude'],
      limit: 100, orderBy: 'status asc, address_line asc',
    })
  }

  async function loadSubscriptions (custFilter) {
    // Service Subscription is the canonical subscription doctype: contracts,
    // chain activation, prorated billing and the "Add service" dialog all
    // converge on it. Stock ERPNext Subscription rows are legacy-migration
    // artefacts (~39k paired at import time) — we no longer create them and
    // we no longer surface them here.
    const subs = await listDocs('Service Subscription', {
      filters: { customer: custFilter.customer },
      fields: ['name', 'plan_name', 'service_category', 'monthly_price', 'billing_cycle',
        'service_location', 'status', 'start_date', 'end_date', 'cancellation_date',
        'contract_duration', 'product_sku', 'speed_down', 'speed_up',
        'radius_user', 'device', 'display_order', 'legacy_service_id'],
      limit: 100,
      // display_order first (dispatcher-controlled), then by start date so
      // newer subs float up when display_order hasn't been set yet (= 0).
      orderBy: 'display_order asc, start_date desc, creation desc',
    })

    // Map Service Subscription → UI row shape (matches what useSubscriptionGroups
    // / useSubscriptionActions / the template consume: `actual_price`, `custom_description`,
    // `billing_frequency`, English status strings, `cancel_at_period_end`).
    const toUiStatus = s => {
      if (s === 'Actif') return 'Active'
      if (s === 'Annulé') return 'Cancelled'
      if (s === 'Suspendu') return 'Suspended'
      if (s === 'En attente') return 'Pending'
      return s || 'Active'
    }

    return subs.map(doc => ({
      name: doc.name,
      subscription: doc.name,
      plan_name: doc.plan_name || '',
      item_code: doc.product_sku || '',
      item_name: doc.plan_name || '',
      item_group: doc.service_category || '',
      custom_description: doc.plan_name || '',
      actual_price: Number(doc.monthly_price || 0),
      service_location: doc.service_location || '',
      billing_frequency: doc.billing_cycle === 'Annuel' ? 'A' : 'M',
      status: toUiStatus(doc.status),
      start_date: doc.start_date,
      end_date: doc.end_date,
      cancel_at_period_end: doc.end_date ? 1 : 0,
      cancelation_date: doc.cancellation_date,
      current_invoice_start: null,
      current_invoice_end: null,
      radius_user: doc.radius_user || '',
      radius_pwd: '',
      device: doc.device || '',
      display_order: Number(doc.display_order || 0),
      legacy_service_id: Number(doc.legacy_service_id || 0), // = service.id de F (0 = ajouté dans ERPNext, pas dans F)
      qty: 1,
    }))
  }

  function loadEquipment (custFilter) {
    return listDocs('Service Equipment', {
      filters: custFilter,
      fields: ['name', 'equipment_type', 'brand', 'model', 'serial_number', 'mac_address',
        'ip_address', 'status', 'service_location',
        'olt_name', 'olt_ip', 'olt_frame', 'olt_slot', 'olt_port', 'olt_ontid'],
      limit: 200, orderBy: 'equipment_type asc',
    })
  }

  function loadTickets (custFilter) {
    return listDocs('Issue', {
      filters: custFilter,
      fields: ['name', 'subject', 'status', 'priority', 'opening_date', 'service_location', 'legacy_ticket_id', 'is_important', 'assigned_staff', 'opened_by_staff', 'issue_type'],
      limit: 10, orderBy: 'is_important desc, opening_date desc',
    })
  }

  function loadInvoices (custFilter) {
    return listDocs('Sales Invoice', {
      filters: custFilter,
      fields: ['name', 'posting_date', 'grand_total', 'outstanding_amount', 'status', 'is_return', 'return_against', 'creation'],
      limit: 5, orderBy: 'posting_date desc, name desc',
    })
  }

  function loadPayments (id) {
    return listDocs('Payment Entry', {
      filters: { party_type: 'Customer', party: id },
      fields: ['name', 'posting_date', 'creation', 'paid_amount', 'mode_of_payment', 'reference_no'],
      limit: 5, orderBy: 'creation desc',
    })
  }

  function loadVoipLines (custFilter) {
    return listDocs('VoIP Line', {
      filters: custFilter,
      fields: ['name', 'did', 'status', 'service_location', 'sip_user', 'sip_host',
        'e911_civic_number', 'e911_street_name', 'e911_municipality', 'e911_synced',
        'ata_model', 'ata_mac'],
      limit: 50, orderBy: 'status asc, did asc',
    }).catch(() => [])
  }

  function loadPaymentMethods (custId) {
    // Fetch via targo-hub which enriches with live Stripe card data
    return fetch(`${_HUB_URL}/payments/methods/${encodeURIComponent(custId)}`, {
      headers: { 'Content-Type': 'application/json' },
    }).then(r => r.json()).then(d => d.methods || []).catch(() => [])
  }

  // Statut de remboursement Stripe par PaymentIntent (1 appel hub → 1 appel Stripe) → badges dans le bloc paiements
  function loadRefunds (custId) {
    return fetch(`${_HUB_URL}/payments/refunds/${encodeURIComponent(custId)}`, {
      headers: { 'Content-Type': 'application/json' },
    }).then(r => r.json()).then(d => d.refunds || {}).catch(() => ({}))
  }

  // Charges Stripe réelles (auto-PPA / lien de paiement) — comble le trou où un paiement Stripe non synchronisé
  // en Payment Entry ERPNext n'apparaissait pas sur la fiche. Lecture seule, non bloquant.
  function loadStripeCharges (custId) {
    return fetch(`${_HUB_URL}/payments/charges/${encodeURIComponent(custId)}`, {
      headers: { 'Content-Type': 'application/json' },
    }).then(r => r.json()).then(d => d.charges || []).catch(() => ([]))
  }

  function loadArrangements (custFilter) {
    return listDocs('Payment Arrangement', {
      filters: custFilter,
      fields: ['name', 'status', 'total_amount', 'payment_method', 'date_agreed', 'date_due', 'date_cutoff', 'staff', 'note'],
      limit: 50, orderBy: 'date_agreed desc',
    }).catch(() => [])
  }

  function loadQuotations (id) {
    // Both legacy (custom_legacy_soumission_id > 0) and new wizard-created
    // Quotations are returned. Filtering only on party_name surfaces both.
    return listDocs('Quotation', {
      filters: { party_name: id },
      fields: ['name', 'transaction_date', 'grand_total', 'status', 'custom_legacy_soumission_id', 'custom_po_number'],
      limit: 50, orderBy: 'transaction_date desc',
    }).catch(() => [])
  }

  function loadServiceContracts (id) {
    // Service Contracts are the "offre de service" artifact — they carry
    // monthly_rate, duration, and benefits (net promotions). Shown alongside
    // Soumissions so the rep can retrieve the recap after publish.
    // `service_subscription` is the Link field ERPNext uses for referential
    // integrity; we need it client-side so delete-sub can detect a live
    // contract and surface termination fees before breaking the link.
    return listDocs('Service Contract', {
      filters: { customer: id },
      fields: ['name', 'contract_type', 'status', 'start_date', 'end_date',
        'duration_months', 'monthly_rate', 'total_benefit_value',
        'quotation', 'acceptance_method', 'signed_at', 'service_subscription'],
      limit: 50, orderBy: 'creation desc',
    }).catch(() => [])
  }

  function loadComments (id) {
    return listDocs('Comment', {
      filters: { reference_doctype: 'Customer', reference_name: id, comment_type: 'Comment' },
      fields: ['name', 'content', 'comment_by', 'creation'],
      limit: 50, orderBy: 'creation desc',
    }).catch(() => [])
  }

  function loadBalance (id) {
    return authFetch(BASE_URL + '/api/method/customer_balance?customer=' + encodeURIComponent(id)).catch(() => null)
  }

  async function loadCustomer (id) {
    resetState()
    try {
      const custFilter = { customer: id }
      const [cust, locs, subs, equip, tix, invs, pays, voip, pmethods, arrgs, quots, contracts, memos, balRes] = await Promise.all([
        getDoc('Customer', id),
        loadLocations(custFilter),
        loadSubscriptions(custFilter),
        loadEquipment(custFilter),
        loadTickets(custFilter),
        loadInvoices(custFilter),
        loadPayments(id),
        loadVoipLines(custFilter),
        loadPaymentMethods(id),
        loadArrangements(custFilter),
        loadQuotations(id),
        loadServiceContracts(id),
        loadComments(id),
        loadBalance(id),
      ])

      for (const f of ['is_commercial', 'is_bad_payer', 'exclude_fees', 'ppa_enabled']) { cust[f] = !!cust[f] }
      customer.value = cust
      locations.value = locs
      subscriptions.value = subs
      invalidateAll()
      equipment.value = equip
      if (equip.length) {
        fetchStatus(equip).catch(() => {})
        for (const eq of equip) {
          if (eq.serial_number) fetchOltStatus(eq.serial_number).catch(() => {})
        }
      }
      tickets.value = tix.sort((a, b) => (b.is_important || 0) - (a.is_important || 0) || (b.opening_date || '').localeCompare(a.opening_date || ''))
      invoices.value = invs
      payments.value = pays
      loadRefunds(id).then(m => { refundsByPi.value = m || {} }) // remboursements Stripe (non bloquant) → badges dans le bloc paiements
      loadStripeCharges(id).then(c => { stripeCharges.value = c || [] }) // charges Stripe réelles (non bloquant) → bloc paiements
      voipLines.value = voip
      paymentMethods.value = pmethods
      arrangements.value = arrgs
      quotations.value = quots
      serviceContracts.value = contracts
      contact.value = null
      comments.value = memos

      if (balRes?.ok) {
        try { accountBalance.value = (await balRes.json()).message } catch {}
      }
    } catch {
      customer.value = null
    } finally {
      loading.value = false
    }
  }

  async function loadAllTickets () {
    if (ticketsExpanded.value || !customer.value) return
    loadingMoreTickets.value = true
    try {
      tickets.value = await listDocs('Issue', {
        filters: { customer: customer.value.name },
        fields: ['name', 'subject', 'status', 'priority', 'opening_date', 'service_location', 'legacy_ticket_id', 'is_important', 'assigned_staff', 'opened_by_staff', 'issue_type'],
        limit: 500, orderBy: 'is_important desc, opening_date desc',
      })
      ticketsExpanded.value = true
    } catch {}
    loadingMoreTickets.value = false
  }

  async function loadAllInvoices () {
    if (invoicesExpanded.value || !customer.value) return
    loadingMoreInvoices.value = true
    try {
      invoices.value = await listDocs('Sales Invoice', {
        filters: { customer: customer.value.name },
        fields: ['name', 'posting_date', 'grand_total', 'outstanding_amount', 'status', 'is_return', 'return_against', 'creation'],
        limit: 200, orderBy: 'posting_date desc, name desc',
      })
      invoicesExpanded.value = true
    } catch {}
    loadingMoreInvoices.value = false
  }

  async function loadAllPayments () {
    if (paymentsExpanded.value || !customer.value) return
    loadingMorePayments.value = true
    try {
      payments.value = await listDocs('Payment Entry', {
        filters: { party_type: 'Customer', party: customer.value.name },
        fields: ['name', 'posting_date', 'creation', 'paid_amount', 'mode_of_payment', 'reference_no'],
        limit: 200, orderBy: 'creation desc',
      })
      paymentsExpanded.value = true
    } catch {}
    loadingMorePayments.value = false
  }

  return {
    loading, customer, contact, locations, subscriptions, tickets,
    invoices, payments, voipLines, paymentMethods, arrangements, quotations,
    serviceContracts, comments, accountBalance, refundsByPi, stripeCharges,
    loadingMoreTickets, loadingMoreInvoices, loadingMorePayments,
    loadCustomer, loadAllTickets, loadAllInvoices, loadAllPayments,
  }
}
