<script setup lang="ts">
/**
 * Print / export. Compiles the current design (injected `ldDesigner`) to a PDF
 * at exact label size via `usePdfCompiler`, then either downloads it or sends
 * it to the existing server print pipeline (POST /api/print/labelprint → CUPS
 * `lp`). Printer list comes from the central registry GET /api/printers
 * (CUST_Printer); the selected printer's DefaultPrintOptions pre-fills options.
 */
import { toast } from 'bulma-toast'

const open = defineModel<boolean>('open', { default: false })

const designer = inject('ldDesigner') as ReturnType<typeof useLabelDesign>
const { template } = designer
const compiler = usePdfCompiler()

const DEFAULT_PRINTERS = ['labelprinter-1', 'labelprinter-2', 'labelprinter-3', 'labelprinter-4', 'labelprinter-5']

interface Printer { name: string; value: string }
const printers = ref<Printer[]>([])
const printerValue = ref<string>(template.value.defaultPrinter || '')
const customPrinter = ref('')
const copies = ref(1)
const printOptions = ref('')
const busy = ref(false)
const alert = ref({ status: '', message: '' })

// cupsName → configured DefaultPrintOptions, used to pre-fill the options field
// when a printer is picked. `lastAutoOptions` lets us refresh the field on
// re-selection without clobbering options the user typed by hand.
const printerOptionsByName = ref<Record<string, string>>({})
let lastAutoOptions = ''

const applyPrinterDefaults = (cups: string) => {
  const def = printerOptionsByName.value[cups] || ''
  if (printOptions.value === '' || printOptions.value === lastAutoOptions) {
    printOptions.value = def
    lastAutoOptions = def
  }
}

const fetchPrinters = async () => {
  try {
    // Central printer registry (CUST_Printer). The CUPS queue name is the value
    // sent to the print pipeline; name/type are display, options are defaults.
    const res: any = await $fetch('/api/printers', { headers: useRequestHeaders(['cookie']) })
    const recs = Array.isArray(res?.records) ? res.records : []
    const seen = new Set<string>()
    const list: Printer[] = []
    const optsMap: Record<string, string> = {}
    let preferred = ''
    for (const r of recs) {
      const cups = r?.cupsName
      if (!cups || seen.has(cups)) continue
      seen.add(cups)
      const typeTag = r?.printerTypeLabel ? ` · ${r.printerTypeLabel}` : ''
      list.push({ name: `${r.name || cups} (${cups})${typeTag}`, value: cups })
      optsMap[cups] = r?.defaultPrintOptions || ''
      if (r?.isDefault && !preferred) preferred = cups
    }
    if (list.length) {
      printers.value = list
      printerOptionsByName.value = optsMap
      // Drop a design's saved printer that no longer exists in the registry.
      if (printerValue.value && printerValue.value !== '__custom__' && !seen.has(printerValue.value)) {
        printerValue.value = ''
      }
      // Selection priority: design's saved printer → a registry default → first.
      if (!printerValue.value) printerValue.value = preferred || printers.value[0].value
    } else {
      printers.value = DEFAULT_PRINTERS.map(p => ({ name: p, value: p }))
      printerOptionsByName.value = {}
      if (!printerValue.value) printerValue.value = printers.value[0].value
    }
  } catch {
    printers.value = DEFAULT_PRINTERS.map(p => ({ name: p, value: p }))
    printerOptionsByName.value = {}
    if (!printerValue.value && printers.value.length) printerValue.value = printers.value[0].value
  }
  applyPrinterDefaults(printerValue.value)
}

watch(open, (v) => { if (v) fetchPrinters() })
watch(printerValue, (v) => { if (v && v !== '__custom__') applyPrinterDefaults(v) })

const resolvedPrinter = computed(() => (printerValue.value === '__custom__' ? customPrinter.value.trim() : printerValue.value))

const slug = () => (template.value.name || 'label').replace(/[^a-z0-9]+/gi, '-').replace(/^-+|-+$/g, '').toLowerCase() || 'label'
const stamp = () => new Date().toISOString().replace(/[-:T.]/g, '_').slice(0, 19)

const download = async () => {
  busy.value = true
  alert.value = { status: '', message: '' }
  try {
    const doc = await compiler.compileToPdf(template.value, { copies: Math.max(1, copies.value), dpi: 300 })
    doc.save(`${slug()}-${stamp()}.pdf`)
  } catch (err: any) {
    alert.value = { status: '500', message: err?.message || 'PDF generation failed' }
  } finally {
    busy.value = false
  }
}

const print = async () => {
  if (!resolvedPrinter.value) {
    alert.value = { status: '400', message: 'Please choose or enter a printer.' }
    return
  }
  busy.value = true
  alert.value = { status: '', message: '' }
  try {
    template.value.defaultPrinter = resolvedPrinter.value
    const doc = await compiler.compileToPdf(template.value, { copies: Math.max(1, copies.value), dpi: 300 })
    const fileContent = compiler.toBase64(doc)
    const res: any = await $fetch('/api/print/labelprint', {
      method: 'POST',
      headers: useRequestHeaders(['cookie']),
      body: {
        pathName: `label-designer/${new Date().getFullYear()}`,
        fileName: `${slug()}-${stamp()}.pdf`,
        fileContent,
        shippingPrinter: resolvedPrinter.value,
        printOptions: printOptions.value || ''
      }
    })
    if (res?.message === 'success' || (res && !res.stderr)) {
      toast({ message: `Sent to ${resolvedPrinter.value}`, type: 'is-success', duration: 2500, position: 'bottom-right' })
      open.value = false
    } else {
      alert.value = { status: '500', message: res?.stderr || res?.message || 'Print failed' }
    }
  } catch (err: any) {
    alert.value = { status: '500', message: err?.message || 'Print failed' }
  } finally {
    busy.value = false
  }
}
</script>

<template>
  <UModal v-model:open="open" :ui="{ content: 'sm:max-w-lg' }">
    <template #content>
      <div class="ldModal">
        <div class="ldModal__head">
          <h3><span class="ti ti-printer mr-1"></span> Print label</h3>
          <button type="button" class="ldModal__close" @click="open = false"><span class="ti ti-x"></span></button>
        </div>

        <div class="ldModal__body">
          <div v-if="alert.status" class="notification is-danger is-light py-2 px-3">{{ alert.message }}</div>

          <div class="ldField">
            <label>Printer</label>
            <div class="select is-fullwidth">
              <select v-model="printerValue">
                <option v-for="p in printers" :key="p.value" :value="p.value">{{ p.name }}</option>
                <option value="__custom__">Custom…</option>
              </select>
            </div>
          </div>
          <div v-if="printerValue === '__custom__'" class="ldField">
            <label>Printer name (CUPS)</label>
            <input class="input" v-model="customPrinter" placeholder="e.g. labelprinter-1" />
          </div>

          <div class="ldGrid2">
            <div class="ldField">
              <label>Copies</label>
              <input type="number" min="1" max="200" class="input" v-model.number="copies" />
            </div>
            <div class="ldField">
              <label>Print options <span class="ldHint">(optional)</span></label>
              <input class="input" v-model="printOptions" placeholder="e.g. -o fit-to-page" />
            </div>
          </div>

          <p class="ldSize">Label: {{ template.size.wMm }} × {{ template.size.hMm }} mm · {{ template.elements.length }} elements</p>
        </div>

        <div class="ldModal__foot">
          <button type="button" class="button" :class="{ 'is-loading': busy }" @click="download"><span class="ti ti-download mr-1"></span> Download PDF</button>
          <button type="button" class="button is-primary" :class="{ 'is-loading': busy }" @click="print"><span class="ti ti-printer mr-1"></span> Print</button>
        </div>
      </div>
    </template>
  </UModal>
</template>

<style scoped>
.ldModal { background: var(--theme-bg-primary, #fff); border-radius: 12px; overflow: hidden; }
.ldModal__head { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid var(--theme-border, #ececef); }
.ldModal__head h3 { font-size: 16px; font-weight: 700; }
.ldModal__close { background: none; border: none; cursor: pointer; font-size: 20px; line-height: 1; opacity: 0.6; }
.ldModal__close:hover { opacity: 1; }
.ldModal__body { padding: 16px 18px; display: flex; flex-direction: column; gap: 12px; }
.ldModal__foot { display: flex; justify-content: flex-end; gap: 8px; padding: 14px 18px; border-top: 1px solid var(--theme-border, #ececef); }
.ldField { display: flex; flex-direction: column; gap: 4px; }
.ldField > label { font-size: 12px; opacity: 0.7; }
.ldHint { opacity: 0.5; }
.ldGrid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.ldSize { font-size: 12px; opacity: 0.6; }
</style>
