<script>
// Module-scope caches: shared across every cell instance AND across all four
// accounting pages, so a given order/invoice preview is fetched at most once.
// (Declared in a plain <script> block so it lives in module scope, not per-setup.)
const AgDocPreviewLink_cache = new Map()
const AgDocPreviewLink_inflight = new Map()
</script>

<script setup>
import { ref, computed, onBeforeUnmount } from 'vue'

// Shared AG Grid cell renderer for the accounting reconciliation grids
// (eBay/Amazon settlements + order checks). Renders the "Interner Auftrag" /
// "Rechnung" cell as a clickable link that:
//   - navigates to the order/invoice EDIT page on click, and
//   - shows a lazily-fetched mini preview card (customer, positions, pricing,
//     total) on hover — teleported to <body> so it escapes the grid's overflow.
//
// Configure per column via cellRendererParams:
//   { kind: 'order' | 'invoice', missingMode?: 'fehlt' | 'zuordnung' }
//   - kind 'order'  : reads data.internalOrderId / data.internalDocumentNo
//   - kind 'invoice': reads data.invoiceId / data.invoiceDocumentNo / data.invoiceExists
//   - missingMode (order only): how to render an unmatched row
//       'fehlt'      → "✗ FEHLT" (or "nicht importiert (storniert)") — orders-check pages
//       'zuordnung'  → "— nicht zugeordnet" — settlement pages

const props = defineProps({ params: Object })

// Module-level caches shared across every cell instance + page, so a given
// order/invoice is fetched at most once per session.
const previewCache = AgDocPreviewLink_cache
const inflight = AgDocPreviewLink_inflight

const reqHeaders = useRequestHeaders(['cookie'])

const data = computed(() => props.params?.data || null)
const kind = computed(() => props.params?.kind || 'order')
const missingMode = computed(() => props.params?.missingMode || 'fehlt')

const docId = computed(() => {
  const d = data.value
  if (!d) return null
  return kind.value === 'invoice' ? (d.invoiceId || null) : (d.internalOrderId || null)
})

const docLabel = computed(() => {
  const d = data.value
  if (!d) return ''
  return kind.value === 'invoice'
    ? (d.invoiceDocumentNo || 'Rechnung')
    : (d.internalDocumentNo || d.internalOrderId || '')
})

const navPath = computed(() => {
  if (!docId.value) return ''
  const base = kind.value === 'invoice' ? '/sales/invoices' : '/sales/orders'
  return `${base}/${docId.value}/edit`
})

// Decide what the cell shows. Mirrors the previous inline renderers exactly.
const view = computed(() => {
  const d = data.value
  if (!d) return { type: 'empty' }

  if (kind.value === 'invoice') {
    if (!d.matched) return { type: 'empty' }
    if (d.invoiceExists) {
      if (d.invoiceId) return { type: 'link' }
      return { type: 'text', text: '✓ Rechnung vorhanden', color: '#2e7d32', bold: true }
    }
    return { type: 'text', text: '— keine Rechnung', color: '#ef6c00', bold: false }
  }

  // order
  if (d.matched && d.internalOrderId) return { type: 'link' }
  if (missingMode.value === 'zuordnung') {
    if (d.orderId) return { type: 'text', text: '— nicht zugeordnet', color: '#c62828', bold: false }
    return { type: 'empty' }
  }
  if (d.isCanceled) return { type: 'text', text: '— nicht importiert (storniert)', color: '#90a4ae', bold: false }
  return { type: 'text', text: '✗ FEHLT', color: '#c62828', bold: true }
})

// ---- Hover preview ---------------------------------------------------------
const linkEl = ref(null)
const show = ref(false)
const loading = ref(false)
const errorMsg = ref('')
const preview = ref(null)
const cardStyle = ref({})
let showTimer = null

const cacheKey = computed(() => `${kind.value}:${docId.value}`)
const previewTitle = computed(() => (kind.value === 'invoice' ? 'Rechnung' : 'Auftrag'))

const positionCard = () => {
  const el = linkEl.value
  if (!el || typeof window === 'undefined') return
  const rect = el.getBoundingClientRect()
  const CARD_W = 360
  const CARD_MAX_H = 400
  const margin = 8
  // Prefer to the right of the cell; flip left if it would overflow.
  let left = rect.right + margin
  if (left + CARD_W > window.innerWidth - margin) {
    left = rect.left - CARD_W - margin
    if (left < margin) left = Math.max(margin, window.innerWidth - CARD_W - margin)
  }
  let top = rect.top
  if (top + CARD_MAX_H > window.innerHeight - margin) {
    top = Math.max(margin, window.innerHeight - CARD_MAX_H - margin)
  }
  cardStyle.value = { left: `${left}px`, top: `${top}px` }
}

const loadPreview = async () => {
  const id = docId.value
  if (!id) return
  const key = cacheKey.value
  if (previewCache.has(key)) { preview.value = previewCache.get(key); return }

  loading.value = true
  errorMsg.value = ''
  try {
    let p = inflight.get(key)
    if (!p) {
      const url = kind.value === 'invoice' ? `/api/invoices/${id}/preview` : `/api/orders/${id}/preview`
      p = $fetch(url, { headers: reqHeaders })
      inflight.set(key, p)
    }
    const res = await p
    inflight.delete(key)
    if (res && Number(res.status) === 200) {
      previewCache.set(key, res)
      preview.value = res
    } else {
      errorMsg.value = res?.message || 'Vorschau nicht verfügbar'
    }
  } catch (e) {
    inflight.delete(key)
    errorMsg.value = e?.data?.message || e?.message || 'Vorschau nicht verfügbar'
  } finally {
    loading.value = false
  }
}

const onEnter = () => {
  if (view.value.type !== 'link') return
  clearTimeout(showTimer)
  showTimer = setTimeout(() => {
    positionCard()
    show.value = true
    preview.value = previewCache.get(cacheKey.value) || null
    loadPreview()
  }, 180)
}

const onLeave = () => {
  clearTimeout(showTimer)
  show.value = false
}

onBeforeUnmount(() => {
  clearTimeout(showTimer)
  show.value = false
})

// ---- Formatting ------------------------------------------------------------
const fmtCur = (v, cur) => {
  const c = cur || preview.value?.currency || 'EUR'
  try {
    return new Intl.NumberFormat('de-DE', { style: 'currency', currency: c, minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(v || 0)
  } catch {
    return `${(Number(v) || 0).toFixed(2)} ${c}`
  }
}
const fmtDate = (s) => {
  if (!s) return ''
  const d = new Date(s)
  return isNaN(d.getTime()) ? s : d.toLocaleDateString('de-DE')
}
const fmtQty = (v) => {
  const n = Number(v || 0)
  return Number.isInteger(n) ? String(n) : n.toLocaleString('de-DE', { maximumFractionDigits: 2 })
}

const MAX_LINES = 8
const shownLines = computed(() => (preview.value?.lines || []).slice(0, MAX_LINES))
const moreLines = computed(() => Math.max(0, (preview.value?.lines?.length || 0) - MAX_LINES))
</script>

<template>
  <span class="agdoc-cell">
    <a
      v-if="view.type === 'link'"
      ref="linkEl"
      :href="navPath"
      target="_blank"
      rel="noopener"
      class="agdoc-link"
      @click="onLeave"
      @mouseenter="onEnter"
      @mouseleave="onLeave"
    >✓ {{ docLabel }}</a>

    <span
      v-else-if="view.type === 'text'"
      :style="{ color: view.color, fontWeight: view.bold ? '700' : '400' }"
    >{{ view.text }}</span>

    <Teleport to="body">
      <div v-if="show" class="agdoc-preview" :style="cardStyle">
        <div class="agdoc-pv-head">
          <span class="agdoc-pv-title">
            <i :class="kind === 'invoice' ? 'ti ti-file-invoice' : 'ti ti-shopping-cart'"></i>
            {{ previewTitle }} {{ preview?.documentNo || docLabel }}
          </span>
          <span v-if="preview?.docStatus" class="agdoc-pv-badge">{{ preview.docStatus }}</span>
        </div>

        <div v-if="loading && !preview" class="agdoc-pv-loading">
          <span class="agdoc-pv-spinner"></span> Vorschau wird geladen …
        </div>

        <div v-else-if="errorMsg && !preview" class="agdoc-pv-error">{{ errorMsg }}</div>

        <template v-else-if="preview">
          <div class="agdoc-pv-meta">
            <div class="agdoc-pv-cust">
              <i class="ti ti-user"></i> {{ preview.partner || '—' }}
            </div>
            <div v-if="preview.date" class="agdoc-pv-date">{{ fmtDate(preview.date) }}</div>
          </div>

          <table class="agdoc-pv-table">
            <thead>
              <tr>
                <th class="agdoc-l">Position</th>
                <th class="agdoc-r">Menge</th>
                <th class="agdoc-r">Preis</th>
                <th class="agdoc-r">Summe</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="(l, i) in shownLines" :key="i">
                <td class="agdoc-l">
                  <span class="agdoc-pv-prod">{{ l.product }}</span>
                  <span v-if="l.sku" class="agdoc-pv-sku">{{ l.sku }}</span>
                </td>
                <td class="agdoc-r">{{ fmtQty(l.qty) }}</td>
                <td class="agdoc-r">{{ fmtCur(l.price, preview.currency) }}</td>
                <td class="agdoc-r">{{ fmtCur(l.lineTotal, preview.currency) }}</td>
              </tr>
              <tr v-if="!shownLines.length">
                <td colspan="4" class="agdoc-pv-empty">Keine Positionen</td>
              </tr>
            </tbody>
          </table>

          <div v-if="moreLines" class="agdoc-pv-more">+{{ moreLines }} weitere Position(en)</div>

          <div class="agdoc-pv-foot">
            <span>Netto: {{ fmtCur(preview.totalLines, preview.currency) }}</span>
            <span class="agdoc-pv-total">Gesamt: {{ fmtCur(preview.grandTotal, preview.currency) }}</span>
          </div>
        </template>
      </div>
    </Teleport>
  </span>
</template>

<!-- NON-scoped on purpose: the preview card is teleported to <body>, where
     scoped-style data-attributes are unreliable (see the teleport + scoped-CSS
     project gotcha). All classes are prefixed `agdoc-` to avoid collisions. -->
<style>
.agdoc-cell { display: inline; }

.agdoc-link {
  color: #2e7d32;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
}
.agdoc-link:hover { text-decoration: underline; }

.agdoc-preview {
  position: fixed;
  z-index: 10000;
  width: 360px;
  max-height: 400px;
  overflow: hidden;
  pointer-events: none;
  background: #fff;
  border: 1px solid #d7dde5;
  border-radius: 8px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
  font-size: 12px;
  color: #2b3440;
  padding: 10px 12px;
}

.agdoc-pv-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  border-bottom: 1px solid #eef1f5;
  padding-bottom: 6px;
  margin-bottom: 6px;
}
.agdoc-pv-title {
  font-weight: 700;
  font-size: 13px;
  color: #1c2530;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.agdoc-pv-title i { color: #3273dc; margin-right: 3px; }
.agdoc-pv-badge {
  flex: none;
  background: #eef2f7;
  color: #5a6675;
  border-radius: 4px;
  padding: 1px 6px;
  font-size: 11px;
  font-weight: 600;
}

.agdoc-pv-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}
.agdoc-pv-cust {
  font-weight: 600;
  color: #2b3440;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.agdoc-pv-cust i { color: #8a94a3; margin-right: 3px; }
.agdoc-pv-date { flex: none; color: #8a94a3; }

.agdoc-pv-table { width: 100%; border-collapse: collapse; }
.agdoc-pv-table th {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: #98a2b3;
  font-weight: 600;
  padding: 2px 4px;
  border-bottom: 1px solid #eef1f5;
}
.agdoc-pv-table td {
  padding: 3px 4px;
  border-bottom: 1px solid #f4f6f9;
  vertical-align: top;
}
.agdoc-l { text-align: left; }
.agdoc-r { text-align: right; white-space: nowrap; }
.agdoc-pv-prod { display: block; font-weight: 600; color: #2b3440; }
.agdoc-pv-sku { display: block; color: #98a2b3; font-size: 10.5px; }
.agdoc-pv-empty { text-align: center; color: #98a2b3; padding: 8px 0; }

.agdoc-pv-more { color: #8a94a3; font-style: italic; margin-top: 4px; }

.agdoc-pv-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-top: 1px solid #eef1f5;
  margin-top: 6px;
  padding-top: 6px;
  font-weight: 600;
}
.agdoc-pv-total { color: #1c2530; font-weight: 700; }

.agdoc-pv-loading { color: #6b7280; padding: 8px 0; display: flex; align-items: center; gap: 6px; }
.agdoc-pv-error { color: #c62828; padding: 8px 0; }
.agdoc-pv-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid #e0e0e0;
  border-bottom-color: #3273dc;
  border-radius: 50%;
  display: inline-block;
  animation: agdoc-rot 0.8s linear infinite;
}
@keyframes agdoc-rot { to { transform: rotate(360deg); } }
</style>
