<template>
  <!-- View toggle -->
  <q-tabs v-model="viewMode" dense align="left" inline-label no-caps
    indicator-color="primary" active-color="primary" class="q-mb-sm"
    style="border-bottom:1px solid var(--ops-border, #e2e8f0)">
    <q-tab name="fields" icon="list_alt" label="Détails" />
    <q-tab name="client" icon="receipt_long" label="Aperçu client" />
  </q-tabs>

  <!-- ══════════ CLIENT PREVIEW ══════════ -->
  <div v-if="viewMode === 'client'" class="q-mb-md">
    <div class="row q-gutter-sm q-mb-sm q-pa-sm" style="background:#f8fafc;border-radius:8px">
      <q-btn outline dense no-caps color="negative" icon="picture_as_pdf" label="Télécharger PDF"
        size="sm" :href="pdfDownloadUrl" target="_blank" />
      <q-btn outline dense no-caps color="primary" icon="content_copy" label="Copier lien paiement"
        size="sm" :loading="generatingPayLink" @click="copyPayLink" />
    </div>
    <iframe :src="clientPreviewUrl" class="invoice-client-preview" />
  </div>

  <!-- ══════════ OPS FIELDS (default) ══════════ -->
  <template v-else>
  <!-- Action bar -->
  <div class="row q-gutter-sm q-mb-md q-pa-sm" style="background:#f8fafc;border-radius:8px">
    <!-- Draft: Submit -->
    <q-btn v-if="isDraft" outline dense no-caps color="green-7" icon="check_circle" label="Soumettre"
      size="sm" :loading="actionLoading" @click="submitInvoice">
      <q-tooltip>Valider et soumettre cette facture</q-tooltip>
    </q-btn>
    <!-- Draft: Delete -->
    <q-btn v-if="isDraft" outline dense no-caps color="negative" icon="delete" label="Supprimer"
      size="sm" :loading="actionLoading" @click="deleteInvoice">
      <q-tooltip>Supprimer ce brouillon</q-tooltip>
    </q-btn>
    <!-- Submitted: Cancel -->
    <q-btn v-if="isSubmitted && !doc.is_return" outline dense no-caps color="warning" icon="cancel" label="Annuler"
      size="sm" :loading="actionLoading" @click="cancelInvoice">
      <q-tooltip>Annuler cette facture</q-tooltip>
    </q-btn>
    <!-- Submitted: Credit Note -->
    <q-btn v-if="isSubmitted && !doc.is_return" outline dense no-caps color="negative" icon="replay" label="Note de credit"
      size="sm" :loading="actionLoading" @click="createCreditNote">
      <q-tooltip>Creer une note de credit (renversement)</q-tooltip>
    </q-btn>
    <!-- Submitted unpaid: Send payment link -->
    <q-btn v-if="isUnpaid" outline dense no-caps color="primary" icon="send" label="Lien paiement"
      size="sm" :loading="sendingLink" @click="sendPaymentLink">
      <q-tooltip>Envoyer un lien de paiement par SMS et courriel</q-tooltip>
    </q-btn>
    <!-- Submitted unpaid: Charge saved card -->
    <q-btn v-if="isUnpaid" outline dense no-caps color="positive" icon="credit_card" label="Charger carte"
      size="sm" :loading="chargingCard" @click="chargeSavedCard">
      <q-tooltip>Debiter la carte enregistree du client</q-tooltip>
    </q-btn>
    <!-- PDF -->
    <q-btn outline dense no-caps color="negative" icon="picture_as_pdf" label="PDF"
      size="sm" @click="$emit('open-pdf', docName)" />
  </div>

  <div class="modal-field-grid">
    <div class="mf"><span class="mf-label">Date</span>{{ doc.posting_date }}</div>
    <div class="mf"><span class="mf-label">Echeance</span>{{ doc.due_date || '---' }}</div>
    <div class="mf"><span class="mf-label">Statut</span><span class="ops-badge" :class="invStatusClass(doc.status)">{{ localStatus || doc.status }}</span></div>
    <div class="mf"><span class="mf-label">Total HT</span>{{ formatMoney(doc.net_total) }}</div>
    <div class="mf"><span class="mf-label">Taxes</span>{{ formatMoney(doc.total_taxes_and_charges) }}</div>
    <div class="mf"><span class="mf-label">Total TTC</span><strong>{{ formatMoney(doc.grand_total) }}</strong></div>
    <div class="mf"><span class="mf-label">Solde du</span><span :class="{'text-red': doc.outstanding_amount > 0}">{{ formatMoney(doc.outstanding_amount) }}</span></div>
    <div class="mf"><span class="mf-label">Devise</span>{{ doc.currency || 'CAD' }}</div>
    <div class="mf" v-if="doc.is_return"><span class="mf-label">Type</span><span class="text-red text-weight-medium">Note de credit</span></div>
    <div class="mf" v-if="doc.return_against"><span class="mf-label">Renversement de</span><a class="text-primary cursor-pointer" @click="$emit('navigate', 'Sales Invoice', doc.return_against, 'Facture ' + doc.return_against)">{{ doc.return_against }}</a></div>
  </div>
  <div class="q-mt-md">
    <div class="info-block-title">Remarques</div>
    <InlineField :value="doc.remarks === 'No Remarks' ? '' : doc.remarks" field="remarks" doctype="Sales Invoice" :docname="docName"
      type="textarea" placeholder="Ajouter des remarques..." @saved="v => doc.remarks = v.value" />
  </div>
  <div v-if="doc.items?.length" class="q-mt-md">
    <div class="info-block-title">Articles ({{ doc.items.length }})</div>
    <DataTable
      :rows="doc.items" :columns="invItemCols" row-key="idx"
      flat dense class="ops-table" hide-pagination :pagination="{ rowsPerPage: 0 }"
    >
      <template #body-cell-amount="p">
        <q-td :props="p" class="text-right">{{ formatMoney(p.row.amount) }}</q-td>
      </template>
      <template #body-cell-rate="p">
        <q-td :props="p" class="text-right">{{ formatMoney(p.row.rate) }}</q-td>
      </template>
    </DataTable>
  </div>
  <div v-if="doc.taxes?.length" class="q-mt-md">
    <div class="info-block-title">Taxes</div>
    <div v-for="t in doc.taxes" :key="t.idx" class="info-row q-py-xs">
      <span>{{ t.description || t.account_head }}</span>
      <q-space />
      <span>{{ formatMoney(t.tax_amount) }}</span>
    </div>
  </div>
  <div v-if="comments.length" class="q-mt-md">
    <div class="info-block-title">Notes ({{ comments.length }})</div>
    <div v-for="mc in comments" :key="mc.name" class="q-py-xs" style="border-bottom:1px solid var(--ops-border, #e2e8f0)">
      <div class="text-caption text-grey-6">{{ mc.comment_by || 'Systeme' }} &middot; {{ formatDateShort(mc.creation) }}</div>
      <div class="text-body2" style="white-space:pre-line">{{ mc.content }}</div>
    </div>
  </div>
  </template>
</template>

<style scoped>
.invoice-client-preview {
  width: 100%;
  min-height: 75vh;
  border: 1px solid var(--ops-border, #e2e8f0);
  border-radius: 8px;
  background: #fff;
}

/* ── Field grid (duplicated from DetailModal.vue — parent scoped styles
   do not cascade into slot component children in Vue SFC). ── */
.modal-field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 16px; }
.mf { display: flex; align-items: baseline; gap: 8px; padding: 6px 0; font-size: 0.875rem; border-bottom: 1px solid #f1f5f9; }
.mf-label { font-size: 0.72rem; font-weight: 600; color: #6b7280; min-width: 80px; flex-shrink: 0; text-transform: uppercase; letter-spacing: 0.03em; }
.info-block-title { font-size: 0.72rem; font-weight: 700; color: #6b7280; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 6px; border-bottom: 1px solid var(--ops-border, #e2e8f0); padding-bottom: 4px; }
.info-row { display: flex; align-items: center; gap: 8px; padding: 2px 0; }
.ops-badge {
  display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 0.7rem;
  font-weight: 600; background: #eef2ff; color: #4338ca;
}
</style>

<script setup>
import { ref, computed } from 'vue'
import DataTable from 'src/components/shared/DataTable.vue'
import { Notify, useQuasar } from 'quasar'
import { formatMoney, formatDateShort } from 'src/composables/useFormatters'
import { invStatusClass } from 'src/composables/useStatusClasses'
import { invItemCols } from 'src/config/table-columns'
import { authFetch } from 'src/api/auth'
import { deleteDoc, getDoc, updateDoc } from 'src/api/erp'
import { BASE_URL } from 'src/config/erpnext'
import InlineField from 'src/components/shared/InlineField.vue'

const HUB_URL = location.hostname === 'localhost' ? 'http://localhost:3300' : (import.meta.env.BASE_URL||'/').replace(/\/$/,'')+'/hub'

const props = defineProps({
  doc: { type: Object, required: true },
  docName: String,
  comments: { type: Array, default: () => [] },
})
const emit = defineEmits(['navigate', 'open-pdf', 'deleted'])

const $q = useQuasar()
const actionLoading = ref(false)
const localStatus = ref(null)
const sendingLink = ref(false)
const chargingCard = ref(false)
const viewMode = ref('fields')
const generatingPayLink = ref(false)

// Client preview = the actual Chromium-rendered PDF (same pipeline the client gets
// via email / QR). Using our whitelisted invoice_pdf endpoint — NOT Frappe's
// /printview (which wraps the template in printview.html and inflates line-heights).
const pdfDownloadUrl = computed(() =>
  `${BASE_URL}/api/method/gigafibre_utils.api.invoice_pdf?name=${encodeURIComponent(props.docName)}`,
)
// #toolbar=0 hides the PDF viewer chrome for a cleaner in-panel look.
const clientPreviewUrl = computed(() => `${pdfDownloadUrl.value}#toolbar=0&navpanes=0&scrollbar=1`)

async function copyPayLink () {
  generatingPayLink.value = true
  try {
    const res = await authFetch(
      `${BASE_URL}/api/method/gigafibre_utils.api.pay_token?invoice=${encodeURIComponent(props.docName)}&ttl_days=30`,
    )
    const data = await res.json()
    const url = data?.message?.url
    if (!url) throw new Error('Pas d\'URL retournée')
    await navigator.clipboard.writeText(url)
    Notify.create({ type: 'positive', message: 'Lien de paiement copié', position: 'top' })
  } catch (e) {
    Notify.create({ type: 'negative', message: `Erreur: ${e.message}`, position: 'top' })
  } finally {
    generatingPayLink.value = false
  }
}

const isDraft = computed(() => props.doc.docstatus === 0)
const isSubmitted = computed(() => props.doc.docstatus === 1)
const isUnpaid = computed(() => isSubmitted.value && !props.doc.is_return && props.doc.outstanding_amount > 0)

// ERPNext workflow calls
async function erpCall (method, args) {
  const res = await authFetch(BASE_URL + '/api/method/' + method, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(args),
  })
  const json = await res.json()
  if (!res.ok) {
    const msg = json?.exception?.split('\n')[0] || json?._server_messages || json?.message || 'Erreur ' + res.status
    throw new Error(msg)
  }
  return json
}

// Hub API calls (for payment operations)
async function hubPost (path, body) {
  const res = await fetch(HUB_URL + path, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  })
  const data = await res.json().catch(() => ({}))
  if (!res.ok) throw new Error(data.error || 'Hub error ' + res.status)
  return data
}

async function submitInvoice () {
  $q.dialog({
    title: 'Soumettre cette facture ?',
    message: `${props.docName} — ${formatMoney(props.doc.grand_total)}\nLa facture sera validee et le solde sera exigible.`,
    cancel: { flat: true, label: 'Annuler' },
    ok: { color: 'green-7', label: 'Soumettre', flat: true },
    persistent: true,
  }).onOk(async () => {
    actionLoading.value = true
    try {
      // Fetch the full doc, set docstatus=1, then amend via frappe.client.submit
      const fullDoc = await getDoc('Sales Invoice', props.docName)
      fullDoc.docstatus = 1
      await erpCall('frappe.client.submit', { doc: fullDoc })
      props.doc.docstatus = 1
      localStatus.value = 'Unpaid'
      props.doc.status = 'Unpaid'
      Notify.create({ type: 'positive', message: `Facture ${props.docName} soumise`, position: 'top' })
    } catch (e) {
      Notify.create({ type: 'negative', message: `Erreur: ${e.message}`, position: 'top' })
    } finally {
      actionLoading.value = false
    }
  })
}

async function cancelInvoice () {
  $q.dialog({
    title: 'Annuler cette facture ?',
    message: `${props.docName} — ${formatMoney(props.doc.grand_total)}\nLa facture sera annulee et le solde remis a zero.`,
    cancel: { flat: true, label: 'Non' },
    ok: { color: 'orange-8', label: 'Annuler la facture', flat: true },
    persistent: true,
  }).onOk(async () => {
    actionLoading.value = true
    try {
      await erpCall('frappe.client.cancel', {
        doctype: 'Sales Invoice',
        name: props.docName,
      })
      props.doc.docstatus = 2
      localStatus.value = 'Cancelled'
      props.doc.status = 'Cancelled'
      Notify.create({ type: 'positive', message: `Facture ${props.docName} annulee`, position: 'top' })
    } catch (e) {
      Notify.create({ type: 'negative', message: `Erreur: ${e.message}`, position: 'top' })
    } finally {
      actionLoading.value = false
    }
  })
}

async function deleteInvoice () {
  $q.dialog({
    title: 'Supprimer ce brouillon ?',
    message: `${props.docName} sera supprime definitivement.`,
    cancel: { flat: true, label: 'Non' },
    ok: { color: 'red-6', label: 'Supprimer', flat: true },
    persistent: true,
  }).onOk(async () => {
    actionLoading.value = true
    try {
      await deleteDoc('Sales Invoice', props.docName)
      Notify.create({ type: 'positive', message: `Facture ${props.docName} supprimee`, position: 'top' })
      emit('deleted', props.docName)
    } catch (e) {
      Notify.create({ type: 'negative', message: `Erreur: ${e.message}`, position: 'top' })
    } finally {
      actionLoading.value = false
    }
  })
}

async function createCreditNote () {
  $q.dialog({
    title: 'Creer une note de credit ?',
    message: `Un renversement complet de ${props.docName} (${formatMoney(props.doc.grand_total)}) sera cree.\nCela annule le solde de cette facture.`,
    cancel: { flat: true, label: 'Non' },
    ok: { color: 'red-7', label: 'Creer note de credit', flat: true },
    persistent: true,
  }).onOk(async () => {
    actionLoading.value = true
    try {
      const result = await erpCall('erpnext.accounts.doctype.sales_invoice.sales_invoice.make_sales_return', {
        source_name: props.docName,
      })
      // result.message is the new Credit Note doc (unsaved)
      const creditDoc = result.message
      if (!creditDoc) throw new Error('No credit note returned')

      // Save the credit note
      const saveRes = await authFetch(BASE_URL + '/api/resource/Sales%20Invoice', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(creditDoc),
      })
      const saved = await saveRes.json()
      if (!saveRes.ok) throw new Error(saved?.exception?.split('\n')[0] || 'Save failed')

      const cnName = saved.data?.name
      if (!cnName) throw new Error('Credit note save returned no name')

      // Submit the credit note — fetch the full saved doc first
      const cnDoc = await getDoc('Sales Invoice', cnName)
      cnDoc.docstatus = 1
      await erpCall('frappe.client.submit', { doc: cnDoc })

      Notify.create({ type: 'positive', message: `Note de credit ${cnName} creee et soumise`, position: 'top', timeout: 5000 })
      emit('navigate', 'Sales Invoice', cnName, 'Note de credit ' + cnName)
    } catch (e) {
      Notify.create({ type: 'negative', message: `Erreur: ${e.message}`, position: 'top' })
    } finally {
      actionLoading.value = false
    }
  })
}

async function sendPaymentLink () {
  $q.dialog({
    title: 'Envoyer un lien de paiement',
    message: `Le client recevra un lien par SMS et courriel pour payer la facture ${props.docName} (${formatMoney(props.doc.outstanding_amount)}).`,
    cancel: { flat: true, label: 'Annuler' },
    ok: { color: 'primary', label: 'Envoyer', flat: true },
    persistent: true,
  }).onOk(async () => {
    sendingLink.value = true
    try {
      const result = await hubPost('/payments/send-link', {
        customer: props.doc.customer,
        invoice: props.docName,
        channel: 'both',
      })
      const sentVia = result.sent?.join(' et ') || 'envoi'
      Notify.create({ type: 'positive', message: `Lien de paiement envoye via ${sentVia}`, position: 'top' })
    } catch (e) {
      Notify.create({ type: 'negative', message: `Erreur: ${e.message}`, position: 'top' })
    } finally {
      sendingLink.value = false
    }
  })
}

async function chargeSavedCard () {
  $q.dialog({
    title: 'Charger la carte du client ?',
    message: `Debiter ${formatMoney(props.doc.outstanding_amount)} de la carte enregistree du client pour la facture ${props.docName}.`,
    cancel: { flat: true, label: 'Annuler' },
    ok: { color: 'teal-7', label: 'Charger', flat: true },
    persistent: true,
  }).onOk(async () => {
    chargingCard.value = true
    try {
      const result = await hubPost('/payments/charge', {
        customer: props.doc.customer,
        invoice: props.docName,
      })
      if (result.ok && result.status === 'succeeded') {
        Notify.create({ type: 'positive', message: `Paiement de ${formatMoney(result.amount)} recu (${result.payment_intent})`, position: 'top' })
        // Refresh the invoice doc
        try {
          const fresh = await getDoc('Sales Invoice', props.docName)
          Object.assign(props.doc, { outstanding_amount: fresh.outstanding_amount, status: fresh.status })
          localStatus.value = fresh.status
        } catch {}
      } else {
        Notify.create({ type: 'warning', message: `Paiement en attente: ${result.status}`, position: 'top' })
      }
    } catch (e) {
      Notify.create({ type: 'negative', message: `Erreur: ${e.message}`, position: 'top' })
    } finally {
      chargingCard.value = false
    }
  })
}
</script>
