<script setup>
import { ref, shallowRef, computed, watch, onMounted, onUnmounted } from 'vue'

// Dashboard "Picking" picklist generator. Opened from the picking card header
// button (all orgs) and from OpenShipmentsModal (per-org). Lets the operator pick
// a sort field and a server printer, builds the A4 picklist PDF, shows a preview,
// and offers download or server-side print — instead of an immediate download.
const open = usePicklistModal()
const param = usePicklistModalParam()
const userCookie = useCookie('logship_user')

const SORT_OPTIONS = [
  { value: 'locator', label: 'Lagerplatz (X, Y, Z)' },
  { value: 'value', label: 'Value' },
  { value: 'sku', label: 'SKU' },
  { value: 'mpn', label: 'MPN' },
  { value: 'upc', label: 'UPC' },
  { value: 'name', label: 'Name' },
  { value: 'qty', label: 'Menge (höchste zuerst)' },
  { value: '', label: 'Nur Organisation' },
]

const PICKLIST_REPRINT_WARNING =
  'Achtung: Die Pickliste wurde bereits bei der Versandgenerierung gedruckt. '
  + 'Diese Funktion ist NUR ein Backup, falls die ursprüngliche Pickliste verloren '
  + 'ging – nicht für den regulären Arbeitsablauf.'

const loadingDocs = ref(false)
const loadingPrinters = ref(false)
const docNos = ref([])
const printers = ref([])

const sortBy = ref('locator')
const serverPrint = ref(false)
const selectedPrinter = ref('')
// Optional: when checked, also (re)print the shipments referenced by the picklist —
// each as its own print job (nothing merged) — in the same order the picklist is sorted.
const printShipments = ref(false)

const generating = ref(false)
const printing = ref(false)
const errorMsg = ref('')
const infoMsg = ref('')

const pdfDoc = shallowRef(null)
const fileName = ref('')
const previewUrl = ref('')
const resultMeta = ref(null)
// Referenced shipments in picklist order ({ id, documentNo }), captured from the generator.
const orderedShipments = ref([])
const shipPrintProgress = ref({ done: 0, total: 0 })

const title = computed(() => param.value?.title
  || (param.value?.org ? `Pickliste – ${param.value.org}` : 'Pickliste – Zu kommissionieren'))

const printerOptions = computed(() => ([
  { value: '', label: 'Standarddrucker' },
  ...printers.value.map(p => ({
    value: p.cupsName,
    label: [p.name || p.cupsName, p.locationDevice].filter(Boolean).join(' · ')
      + (p.printerType === 'pap' ? '' : p.printerTypeLabel ? ` (${p.printerTypeLabel})` : ''),
  })),
]))

const selectedPrinterLabel = computed(() =>
  printerOptions.value.find(o => o.value === selectedPrinter.value)?.label || 'Standarddrucker')

const revokePreview = () => {
  if (previewUrl.value) {
    URL.revokeObjectURL(previewUrl.value)
    previewUrl.value = ''
  }
}

const resetState = () => {
  errorMsg.value = ''
  infoMsg.value = ''
  generating.value = false
  printing.value = false
  pdfDoc.value = null
  fileName.value = ''
  resultMeta.value = null
  orderedShipments.value = []
  shipPrintProgress.value = { done: 0, total: 0 }
  revokePreview()
  sortBy.value = 'locator'
  serverPrint.value = false
  printShipments.value = false
  docNos.value = []
}

const loadDocNos = async () => {
  // OpenShipmentsModal already has the shipment list — reuse it if passed.
  if (Array.isArray(param.value?.docNos) && param.value.docNos.length) {
    docNos.value = param.value.docNos.filter(Boolean)
    return
  }
  loadingDocs.value = true
  try {
    const qs = param.value?.org ? `?org=${encodeURIComponent(param.value.org)}` : ''
    const res = await $fetch(`/api/inouts/open-to-commission-list${qs}`, {
      headers: useRequestHeaders(['cookie'])
    })
    docNos.value = (res?.records || []).map(r => r.documentNo).filter(Boolean)
  } catch (e) {
    errorMsg.value = e?.message || 'Fehler beim Laden der Sendungen.'
  } finally {
    loadingDocs.value = false
  }
}

const loadPrinters = async () => {
  loadingPrinters.value = true
  try {
    const res = await $fetch('/api/printers', { headers: useRequestHeaders(['cookie']) })
    printers.value = res?.records || []
    // Prefer a paper/A4 printer (the picklist is A4); fall back to any default.
    const paper = printers.value.filter(p => p.printerType === 'pap')
    const pick = paper.find(p => p.isDefault) || paper[0]
      || printers.value.find(p => p.isDefault) || printers.value[0]
    selectedPrinter.value = pick?.cupsName || ''
  } catch (e) {
    printers.value = []
    selectedPrinter.value = ''
  } finally {
    loadingPrinters.value = false
  }
}

const generate = async () => {
  if (generating.value || !docNos.value.length) return
  errorMsg.value = ''
  infoMsg.value = ''
  generating.value = true
  try {
    const { generate: build } = useGenerateOpenPicklistPdf()
    const res = await build({
      docNos: docNos.value,
      sortBy: sortBy.value,
      userName: userCookie.value?.Name || 'SUPERUSER',
      title: title.value + ' (Reprint)',
    })
    if (!res?.ok) {
      errorMsg.value = res?.reason === 'no-lines'
        ? 'Keine Positionen zum Kommissionieren gefunden.'
        : 'Pickliste konnte nicht erstellt werden.'
      pdfDoc.value = null
      orderedShipments.value = []
      revokePreview()
      resultMeta.value = null
      return
    }
    pdfDoc.value = res.pdf
    fileName.value = res.fileName
    resultMeta.value = { count: res.count, docs: res.docs }
    orderedShipments.value = res.orderedShipments || []
    revokePreview()
    res.pdf.getBlob((blob) => {
      previewUrl.value = URL.createObjectURL(blob)
    })
  } catch (e) {
    errorMsg.value = e?.message || 'Fehler beim Erstellen der Pickliste.'
  } finally {
    generating.value = false
  }
}

const download = () => {
  if (!pdfDoc.value) return
  pdfDoc.value.download(fileName.value)
}

// Re-print each referenced shipment as its own print job — nothing is merged — in the
// picklist's order. Fetches the real m_inout PDF from iDempiere per shipment (we never
// create shipments) and routes each to the same printer as the picklist.
const printShipmentDocs = async () => {
  let success = 0
  let fail = 0
  const list = orderedShipments.value.filter(s => s?.id != null)
  shipPrintProgress.value = { done: 0, total: list.length }
  const stamp = new Date().toISOString().replace(/[-:T]/g, '_').slice(0, 19)
  const userName = userCookie.value?.Name || 'SUPERUSER'
  const year = new Date().getFullYear()
  for (const sh of list) {
    try {
      const pdfRes = await $fetch(`/api/inouts/${sh.id}/print/PDF`, {
        headers: useRequestHeaders(['cookie'])
      })
      if (pdfRes?.reportFile) {
        const printRes = await $fetch('/api/print/picklist', {
          method: 'POST',
          headers: useRequestHeaders(['cookie']),
          body: {
            pathName: `shipments/${year}`,
            fileName: `${stamp}-${sh.documentNo || sh.id}-SHIPMENT-${userName}.pdf`,
            fileContent: pdfRes.reportFile,
            printer: selectedPrinter.value || 'default',
          }
        })
        if (printRes?.message === 'success') success++
        else fail++
      } else {
        fail++
      }
    } catch (e) {
      fail++
    } finally {
      shipPrintProgress.value = { done: shipPrintProgress.value.done + 1, total: list.length }
    }
  }
  return { success, fail }
}

const serverPrintNow = async () => {
  if (printing.value || !pdfDoc.value) return
  printing.value = true
  errorMsg.value = ''
  infoMsg.value = ''
  shipPrintProgress.value = { done: 0, total: 0 }
  let picklistOk = false
  try {
    const base64 = await new Promise((resolve) => pdfDoc.value.getBase64((b) => resolve(b)))
    const res = await $fetch('/api/print/picklist', {
      method: 'POST',
      headers: useRequestHeaders(['cookie']),
      body: {
        pathName: `picklist/${new Date().getFullYear()}`,
        fileName: fileName.value,
        fileContent: base64,
        printer: selectedPrinter.value || 'default',
      }
    })
    if (res?.stderr) errorMsg.value = 'Druckfehler (Pickliste): ' + res.stderr
    else picklistOk = true
  } catch (e) {
    errorMsg.value = e?.message || 'Druckfehler — bitte erneut versuchen.'
  }

  // Optional: also print the shipments referenced by the picklist, in the same order.
  let shipText = ''
  if (printShipments.value && orderedShipments.value.some(s => s?.id != null)) {
    const { success, fail } = await printShipmentDocs()
    shipText = ` · ${success} ${success === 1 ? 'Sendung' : 'Sendungen'} gedruckt`
      + (fail ? `, ${fail} fehlgeschlagen` : '')
  }

  if (picklistOk) {
    infoMsg.value = `Pickliste an „${selectedPrinterLabel.value}“ gesendet${shipText}.`
  } else if (shipText) {
    infoMsg.value = `Sendungen gedruckt${shipText}.`
  }
  printing.value = false
}

const close = () => { open.value = false }

watch(open, async (val) => {
  if (!val) { resetState(); return }
  resetState()
  await Promise.all([loadDocNos(), loadPrinters()])
})

const onKey = (e) => { if (e.key === 'Escape' && open.value) close() }
onMounted(() => window.addEventListener('keydown', onKey))
onUnmounted(() => { window.removeEventListener('keydown', onKey); revokePreview() })
</script>

<template>
  <Teleport to="body">
    <div v-if="open" class="pgm-overlay" @click.self="close">
      <div class="pgm-container" @click.stop>
        <header class="pgm-header">
          <div class="pgm-header__title">
            <span class="pgm-header__icon"><i class="ti ti-printer"></i></span>
            <h3>{{ title }}</h3>
          </div>
          <button type="button" class="pgm-close" @click="close" title="Schließen">
            <i class="ti ti-x"></i>
          </button>
        </header>

        <div class="pgm-body">
          <p class="pgm-warning"><i class="ti ti-alert-triangle"></i> {{ PICKLIST_REPRINT_WARNING }}</p>

          <!-- Options -->
          <div class="pgm-options">
            <div class="pgm-field">
              <label class="pgm-label">Sortierung</label>
              <select v-model="sortBy" class="pgm-select">
                <option v-for="o in SORT_OPTIONS" :key="o.value" :value="o.value">{{ o.label }}</option>
              </select>
            </div>

            <div class="pgm-field pgm-field--check">
              <label class="pgm-check" title="Druckt zusätzlich jeden referenzierten Sendungsbeleg einzeln (nicht zusammengeführt) in der gewählten Reihenfolge.">
                <input type="checkbox" v-model="printShipments" />
                <span>Sendungen mitdrucken</span>
              </label>
            </div>

            <div class="pgm-field pgm-field--check">
              <label class="pgm-check">
                <input type="checkbox" v-model="serverPrint" />
                <span>Auf Server drucken</span>
              </label>
            </div>

            <div v-if="serverPrint" class="pgm-field">
              <label class="pgm-label">Drucker</label>
              <select v-model="selectedPrinter" class="pgm-select" :disabled="loadingPrinters">
                <option v-for="o in printerOptions" :key="o.value" :value="o.value">{{ o.label }}</option>
              </select>
            </div>

            <div class="pgm-field pgm-field--grow"></div>

            <button
              type="button"
              class="pgm-btn pgm-btn--primary"
              :disabled="generating || loadingDocs || !docNos.length"
              @click="generate"
            >
              <i :class="generating ? 'ti ti-loader-2 pgm-spin' : 'ti ti-file-text'"></i>
              {{ pdfDoc ? 'Neu erstellen' : 'Pickliste erstellen' }}
            </button>
          </div>

          <p v-if="printShipments" class="pgm-hint">
            <i class="ti ti-info-circle"></i>
            <span>
              {{ orderedShipments.length || docNos.length }} Sendungsbeleg(e) werden zusätzlich
              einzeln in dieser Reihenfolge gedruckt – die Pickliste selbst bleibt unverändert.
            </span>
          </p>

          <p v-if="!loadingDocs && !docNos.length" class="pgm-state">Keine offenen Sendungen zum Kommissionieren.</p>
          <p v-else-if="loadingDocs" class="pgm-state"><i class="ti ti-loader-2 pgm-spin"></i> Lade Sendungen…</p>

          <p v-if="errorMsg" class="pgm-msg pgm-msg--error">{{ errorMsg }}</p>
          <p v-if="infoMsg" class="pgm-msg pgm-msg--ok">{{ infoMsg }}</p>

          <!-- Preview -->
          <div class="pgm-preview">
            <div v-if="generating" class="pgm-preview-empty"><i class="ti ti-loader-2 pgm-spin"></i> Erstelle Pickliste…</div>
            <iframe v-else-if="previewUrl" :src="previewUrl" class="pgm-preview-frame" title="Pickliste Vorschau"></iframe>
            <div v-else class="pgm-preview-empty">
              <i class="ti ti-file-text"></i>
              <span>Vorschau erscheint hier nach dem Erstellen.</span>
            </div>
          </div>
        </div>

        <footer class="pgm-footer">
          <span class="pgm-count" v-if="resultMeta">
            {{ resultMeta.count }} {{ resultMeta.count === 1 ? 'Position' : 'Positionen' }} ·
            {{ resultMeta.docs }} {{ resultMeta.docs === 1 ? 'Sendung' : 'Sendungen' }}
            <template v-if="printShipments"> · Sendungen werden mitgedruckt</template>
          </span>
          <span class="pgm-count" v-else></span>
          <div class="pgm-footer__actions">
            <button type="button" class="pgm-btn" @click="close">Schließen</button>
            <button
              type="button"
              class="pgm-btn"
              :disabled="!pdfDoc"
              @click="download"
            >
              <i class="ti ti-download"></i> Herunterladen
            </button>
            <button
              type="button"
              class="pgm-btn pgm-btn--primary"
              :disabled="!pdfDoc || printing"
              @click="serverPrintNow"
              :title="`Drucken auf: ${selectedPrinterLabel}`"
            >
              <i :class="printing ? 'ti ti-loader-2 pgm-spin' : 'ti ti-printer'"></i>
              <template v-if="printing && shipPrintProgress.total">
                Sendungen {{ shipPrintProgress.done }}/{{ shipPrintProgress.total }}…
              </template>
              <template v-else>
                {{ printShipments ? 'Pickliste + Sendungen drucken' : 'Auf Server drucken' }}
              </template>
            </button>
          </div>
        </footer>
      </div>
    </div>
  </Teleport>
</template>

<style>
/* Unscoped — Teleport target is <body>; scoped styles wouldn't apply. */
.pgm-overlay {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.55);
  display: flex; align-items: center; justify-content: center;
  z-index: 7100; padding: 1.5rem;
}
.pgm-container {
  width: 100%; max-width: 900px; max-height: 92vh;
  background: var(--theme-bg-primary, #fff);
  color: var(--theme-text-primary, #0f172a);
  border-radius: 10px; overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
}
.pgm-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.875rem 1rem;
  background: linear-gradient(180deg, rgba(244, 63, 94, 0.10), transparent);
  border-bottom: 1px solid var(--theme-border, #e6e8ec);
}
.pgm-header__title { display: flex; align-items: center; gap: 0.625rem; }
.pgm-header__title h3 { margin: 0; font-size: 1rem; font-weight: 700; }
.pgm-header__icon {
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  background: #f43f5e; color: #fff; border-radius: 8px;
}
.pgm-close {
  background: transparent; border: 0; cursor: pointer;
  width: 32px; height: 32px; border-radius: 6px;
  color: var(--theme-text-secondary, #64748b);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 1.1rem;
}
.pgm-close:hover { background: var(--theme-bg-secondary, #f1f5f9); }
.pgm-body { flex: 1; overflow: auto; padding: 0.875rem 1rem 1rem; display: flex; flex-direction: column; gap: 0.75rem; }
.pgm-warning {
  display: flex; align-items: flex-start; gap: 0.45rem; margin: 0;
  font-size: 0.78rem; line-height: 1.35;
  color: #92400e; background: #fffbeb; border: 1px solid #fde68a;
  padding: 0.5rem 0.65rem; border-radius: 6px;
}
.pgm-warning i { margin-top: 1px; }
.pgm-options {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.75rem;
}
.pgm-field { display: flex; flex-direction: column; gap: 0.25rem; min-width: 160px; }
.pgm-field--grow { flex: 1; min-width: 0; }
.pgm-field--check { justify-content: flex-end; min-width: auto; }
.pgm-label { font-size: 0.72rem; font-weight: 600; color: var(--theme-text-secondary, #475569); }
.pgm-select {
  height: 36px; padding: 0 0.55rem; border-radius: 6px;
  border: 1px solid var(--theme-border, #d8dce2);
  background: var(--theme-bg-primary, #fff); color: inherit; font-size: 0.85rem;
}
.pgm-check { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; cursor: pointer; height: 36px; }
.pgm-check input { width: 16px; height: 16px; cursor: pointer; }
.pgm-state {
  display: flex; align-items: center; justify-content: center; gap: 0.5rem;
  margin: 0; padding: 0.5rem; color: var(--theme-text-secondary, #64748b); font-size: 0.85rem;
}
.pgm-msg { margin: 0; padding: 0.45rem 0.65rem; border-radius: 6px; font-size: 0.82rem; }
.pgm-msg--error { color: #b91c1c; background: rgba(244, 63, 94, 0.10); }
.pgm-msg--ok { color: #166534; background: rgba(34, 197, 94, 0.12); }
.pgm-hint {
  display: flex; align-items: flex-start; gap: 0.4rem; margin: 0;
  font-size: 0.78rem; line-height: 1.35;
  color: var(--theme-text-secondary, #475569);
  background: rgba(59, 130, 246, 0.08);
  border: 1px solid rgba(59, 130, 246, 0.18);
  padding: 0.45rem 0.6rem; border-radius: 6px;
}
.pgm-hint i { margin-top: 1px; }
[data-mode="dark"] .pgm-hint { color: #cbd5e1; background: rgba(59, 130, 246, 0.10); border-color: rgba(59, 130, 246, 0.25); }
.pgm-preview {
  flex: 1; min-height: 340px;
  border: 1px solid var(--theme-border, #e6e8ec); border-radius: 8px; overflow: hidden;
  background: var(--theme-bg-secondary, #f8fafc);
  display: flex; align-items: center; justify-content: center;
}
.pgm-preview-frame { width: 100%; height: 100%; min-height: 340px; border: 0; background: #fff; }
.pgm-preview-empty {
  display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
  color: var(--theme-text-secondary, #94a3b8); font-size: 0.85rem;
}
.pgm-preview-empty i { font-size: 1.8rem; }
.pgm-footer {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  padding: 0.625rem 1rem;
  border-top: 1px solid var(--theme-border, #eef0f3);
  background: var(--theme-bg-secondary, #fafbfc);
}
.pgm-count { font-size: 0.8125rem; color: var(--theme-text-secondary, #64748b); }
.pgm-footer__actions { display: inline-flex; align-items: center; gap: 0.5rem; }
.pgm-btn {
  background: var(--theme-bg-primary, #fff);
  color: var(--theme-text-primary, #0f172a);
  border: 1px solid var(--theme-border, #d8dce2); cursor: pointer;
  padding: 0.45rem 0.85rem; border-radius: 6px; font-weight: 600; font-size: 0.85rem;
  display: inline-flex; align-items: center; gap: 0.4rem;
}
.pgm-btn:hover { background: var(--theme-bg-secondary, #f1f5f9); }
.pgm-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.pgm-btn--primary { background: #f43f5e; color: #fff; border-color: #f43f5e; }
.pgm-btn--primary:hover { background: #e11d48; }
.pgm-spin { animation: pgm-spin 0.9s linear infinite; }
@keyframes pgm-spin { to { transform: rotate(360deg); } }
[data-mode="dark"] .pgm-container { background: #0f172a; color: #e2e8f0; }
[data-mode="dark"] .pgm-select { background: #0b1220; border-color: rgba(255,255,255,0.12); }
[data-mode="dark"] .pgm-preview { background: rgba(255,255,255,0.03); border-color: rgba(255,255,255,0.08); }
[data-mode="dark"] .pgm-btn { background: rgba(255,255,255,0.04); border-color: rgba(255,255,255,0.12); color: #e2e8f0; }
[data-mode="dark"] .pgm-footer { background: rgba(255,255,255,0.03); border-color: rgba(255,255,255,0.08); }
[data-mode="dark"] .pgm-warning { color: #fcd34d; background: rgba(251, 191, 36, 0.08); border-color: rgba(251, 191, 36, 0.25); }
</style>
