<script setup>
// Selective JTL → iDempiere product update.
// Pick specific JTL products (by jfsku) AND specific fields, then PREVIEW (no write) or APPLY.
// Backend re-fetches fresh JTL data and PUTs ONLY the chosen fields onto the matching iDempiere
// product (it never creates). See server/api/ffn/selective-update-products.post.ts +
// Laravel FulfillerController::selectiveUpdateProducts.
const props = defineProps({
  open: { type: Boolean, default: false },
  orderSourceId: { type: [String, Number], default: '' },
  jtlMerchantId: { type: String, default: '' },
  orderSourceName: { type: String, default: '' },
})
const emit = defineEmits(['update:open'])

// Field keys MUST match IdempiereProductRepository::selectiveFieldBuilders() (Laravel).
const FIELD_CATALOG = [
  { key: 'name',          label: 'Name' },
  { key: 'sku',           label: 'SKU' },
  { key: 'price',         label: 'Price (gross)' },
  { key: 'weight',        label: 'Weight' },
  { key: 'dimensions',    label: 'Dimensions (W/L/H)' },
  { key: 'ean',           label: 'EAN (UPC)' },
  { key: 'upc',           label: 'UPC (UPC2)' },
  { key: 'asin',          label: 'ASIN' },
  { key: 'mpn',           label: 'MPN' },
  { key: 'fnsku',         label: 'FNSKU', hint: 'Amazon FNSKU (Fulfillment Network SKU) as reported by JTL — writes M_Product.fnsku. Not related to the JTL JF SKU.' },
  { key: 'netWeight',     label: 'Net weight' },
  { key: 'customsTariff', label: 'Customs tariff (TARIC)', hint: 'Writes both M_Product.CustomsTariffNumber and M_Product.taricCode' },
  { key: 'originCountry', label: 'Origin country', hint: 'Writes M_Product.C_Country_ID (resolved from the JTL origin country code)' },
  { key: 'isJtlBom',      label: 'Is BOM (isJtlBom)', hint: 'Writes M_Product.isJtlBom = true/false from the JTL "is bill of materials" flag (the column must exist in iDempiere)' },
]
const MAX_VISIBLE = 300 // cap rendered rows; refine the search to narrow down

const loading = ref(false)
const products = ref([])          // [{ name, merchantSku, jfsku }]
const loadError = ref('')
const search = ref('')
const pick = reactive({})         // jfsku -> bool
const fields = ref([])            // selected field keys

const running = ref(false)
const runError = ref('')
const result = ref(null)          // { success, message, summary, results, dry_run, fields_unknown }

const close = () => emit('update:open', false)

const filtered = computed(() => {
  const q = search.value.trim().toLowerCase()
  const list = q
    ? products.value.filter(p =>
        (p.name || '').toLowerCase().includes(q) ||
        (p.merchantSku || '').toLowerCase().includes(q) ||
        (p.jfsku || '').toLowerCase().includes(q))
    : products.value
  return list
})
const visible = computed(() => filtered.value.slice(0, MAX_VISIBLE))
const overflow = computed(() => Math.max(0, filtered.value.length - MAX_VISIBLE))

const selectedJfskus = computed(() => Object.keys(pick).filter(k => pick[k]))
const selectedCount = computed(() => selectedJfskus.value.length)

const selectAllFiltered = () => { for (const p of filtered.value) if (p.jfsku) pick[p.jfsku] = true }
const clearSelection = () => { for (const k of Object.keys(pick)) pick[k] = false }

const loadProducts = async () => {
  if (!props.orderSourceId) { loadError.value = 'Save the Order Source first.'; return }
  loading.value = true; loadError.value = ''
  try {
    const res = await $fetch('/api/ffn/products-list', {
      method: 'POST',
      headers: useRequestHeaders(['cookie']),
      body: { orderSourceId: props.orderSourceId },
    })
    if (res?.success) products.value = res.products || []
    else loadError.value = res?.message || 'Could not load products'
  } catch (e) {
    loadError.value = e?.data?.message || e?.message || 'Could not load products'
  }
  loading.value = false
}

const submit = async (dryRun) => {
  runError.value = ''; result.value = null
  if (!selectedCount.value) { runError.value = 'Select at least one product.'; return }
  if (!fields.value.length) { runError.value = 'Select at least one field.'; return }
  if (!dryRun && !confirm(`Apply update to ${selectedCount.value} product(s) in iDempiere?\nFields: ${fields.value.join(', ')}`)) return

  running.value = true
  try {
    const res = await $fetch('/api/ffn/selective-update-products', {
      method: 'POST',
      headers: useRequestHeaders(['cookie']),
      body: { orderSourceId: props.orderSourceId, jfskus: selectedJfskus.value, fields: fields.value, dryRun },
    })
    if (res?.success) result.value = res
    else runError.value = res?.message || 'Update failed'
  } catch (e) {
    runError.value = e?.data?.message || e?.message || 'Request failed'
  }
  running.value = false
}

const statusClass = (s) => ({
  updated: 'is-success', preview: 'is-info', failed: 'is-danger', error: 'is-danger',
  not_found_idempiere: 'is-warning', not_in_jtl: 'is-warning', no_change: 'is-light',
}[s] || 'is-light')

const payloadEntries = (p) => Object.entries(p || {}).map(([k, v]) => `${k}: ${v}`)

// Load the product list the first time the modal opens.
watch(() => props.open, (v) => {
  if (v && !products.value.length && !loading.value) loadProducts()
})
</script>

<template>
  <div class="modal" :class="{ 'is-active': open }">
    <div class="modal-background" @click="close"></div>
    <div class="modal-card jsu-card">
      <header class="modal-card-head">
        <p class="modal-card-title">
          <i class="ti ti-edit me-2"></i>
          Selective JTL → iDempiere update
          <span v-if="orderSourceName" class="has-text-grey is-size-6">· {{ orderSourceName }}</span>
        </p>
        <button class="delete" aria-label="close" @click="close"></button>
      </header>

      <section class="modal-card-body">
        <p class="is-size-7 has-text-grey mb-4">
          <i class="ti ti-info-circle me-1"></i>
          Pick the products and the fields you want to push. Fresh JTL data is written to the matching
          iDempiere product — <strong>only the selected fields</strong>. Existing products only (never created).
          Use <strong>Preview</strong> to see exactly what would be written before applying.
        </p>

        <div class="columns">
          <!-- Products -->
          <div class="column is-two-thirds">
            <div class="jsu-section-head">
              <span><i class="ti ti-package me-1"></i> Products <span class="tag is-light ml-1">{{ selectedCount }} selected</span></span>
              <button type="button" class="button is-small is-light" :disabled="loading" @click="loadProducts">
                <i class="ti ti-refresh me-1"></i> Reload
              </button>
            </div>

            <div class="field jsu-search">
              <p class="control has-icons-left">
                <input v-model="search" class="input is-small" type="text" placeholder="Search name, SKU or JFSKU…" />
                <span class="icon is-small is-left"><i class="ti ti-search"></i></span>
              </p>
              <div class="buttons are-small mb-0">
                <button type="button" class="button is-link is-light" :disabled="!filtered.length" @click="selectAllFiltered">Select all (filtered)</button>
                <button type="button" class="button is-light" :disabled="!selectedCount" @click="clearSelection">Clear</button>
              </div>
            </div>

            <div v-if="loading" class="has-text-centered p-5 has-text-grey">
              <i class="ti ti-loader-2 os-spin" style="font-size:1.5rem"></i>
              <div class="mt-2 is-size-7">Loading products from JTL…</div>
            </div>
            <div v-else-if="loadError" class="notification is-danger is-light is-size-7">{{ loadError }}</div>
            <div v-else class="jsu-list">
              <table class="table is-narrow is-fullwidth is-hoverable is-size-7">
                <thead><tr><th style="width:36px"></th><th>Name</th><th>SKU</th><th>JFSKU</th></tr></thead>
                <tbody>
                  <tr v-for="p in visible" :key="p.jfsku" @click="p.jfsku && (pick[p.jfsku] = !pick[p.jfsku])" style="cursor:pointer">
                    <td><input type="checkbox" v-model="pick[p.jfsku]" :disabled="!p.jfsku" @click.stop /></td>
                    <td>{{ p.name || '—' }}</td>
                    <td>{{ p.merchantSku || '—' }}</td>
                    <td>{{ p.jfsku || '—' }}</td>
                  </tr>
                </tbody>
              </table>
              <p v-if="!products.length" class="has-text-grey is-size-7 p-3">No products. Click Reload.</p>
              <p v-else-if="!filtered.length" class="has-text-grey is-size-7 p-3">No products match “{{ search }}”.</p>
              <p v-if="overflow" class="has-text-grey is-size-7 p-2">…and {{ overflow }} more — refine the search to see them.</p>
            </div>
          </div>

          <!-- Fields -->
          <div class="column is-one-third">
            <div class="jsu-section-head"><span><i class="ti ti-list-check me-1"></i> Fields to update</span></div>
            <div class="jsu-fields">
              <label v-for="f in FIELD_CATALOG" :key="f.key" class="jsu-field" :title="f.hint || ''">
                <input type="checkbox" :value="f.key" v-model="fields" />
                <span>{{ f.label }}</span>
                <i v-if="f.hint" class="ti ti-info-circle has-text-grey ml-1" :title="f.hint"></i>
              </label>
            </div>
            <p class="is-size-7 has-text-grey mt-2">{{ fields.length }} field(s) selected</p>
          </div>
        </div>

        <!-- Result -->
        <div v-if="runError" class="notification is-danger is-light is-size-7">{{ runError }}</div>
        <div v-if="result" class="jsu-result">
          <div class="notification is-size-7 mb-2" :class="result.dry_run ? 'is-info is-light' : (result.summary && result.summary.errors ? 'is-warning is-light' : 'is-success is-light')">
            <div>{{ result.message }}</div>
            <div v-if="result.summary" class="tags mt-2 mb-0">
              <span v-for="(v, k) in result.summary" :key="k" class="tag is-white"><strong class="me-1">{{ k }}:</strong> {{ v }}</span>
            </div>
            <div v-if="result.fields_unknown && result.fields_unknown.length" class="mt-2 has-text-danger">
              Skipped fields (unknown/disabled): {{ result.fields_unknown.join(', ') }}
            </div>
          </div>
          <div class="jsu-list">
            <table class="table is-narrow is-fullwidth is-size-7">
              <thead><tr><th>JFSKU</th><th>Name</th><th>Status</th><th>{{ result.dry_run ? 'Would write' : 'Written / detail' }}</th></tr></thead>
              <tbody>
                <tr v-for="(r, i) in result.results" :key="r.jfsku || i">
                  <td>{{ r.jfsku }}</td>
                  <td>{{ r.name || '—' }}</td>
                  <td><span class="tag" :class="statusClass(r.status)">{{ r.status }}</span></td>
                  <td>
                    <template v-if="r.payload && Object.keys(r.payload).length">
                      <span v-for="e in payloadEntries(r.payload)" :key="e" class="tag is-light mr-1 mb-1">{{ e }}</span>
                    </template>
                    <span v-if="r.price" class="tag is-light mr-1 mb-1">price: {{ r.price.value }}</span>
                    <span v-if="r.message" class="has-text-grey">{{ r.message }}</span>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>
      </section>

      <footer class="modal-card-foot is-justify-content-space-between">
        <span class="is-size-7 has-text-grey">{{ selectedCount }} product(s) · {{ fields.length }} field(s)</span>
        <div class="buttons mb-0">
          <button type="button" class="button" @click="close">Close</button>
          <button type="button" class="button is-info" :disabled="running || !selectedCount || !fields.length" @click="submit(true)">
            <i :class="running ? 'ti ti-loader-2 os-spin' : 'ti ti-eye'" class="me-1"></i> Preview
          </button>
          <button type="button" class="button is-primary" :disabled="running || !selectedCount || !fields.length" @click="submit(false)">
            <i :class="running ? 'ti ti-loader-2 os-spin' : 'ti ti-cloud-upload'" class="me-1"></i> Apply update
          </button>
        </div>
      </footer>
    </div>
  </div>
</template>

<style scoped>
.jsu-card { width: 1000px; max-width: 96vw; }
.jsu-section-head { display: flex; align-items: center; justify-content: space-between; font-weight: 600; margin-bottom: .5rem; }
.jsu-search { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; margin-bottom: .5rem; }
.jsu-search .control { flex: 1 1 220px; margin-bottom: 0; }
.jsu-list { max-height: 320px; overflow: auto; border: 1px solid var(--theme-border, #e5e7eb); border-radius: 6px; }
.jsu-list table { margin-bottom: 0; }
.jsu-fields { display: flex; flex-direction: column; gap: .4rem; max-height: 320px; overflow: auto; padding: .25rem; }
.jsu-field { display: flex; align-items: center; gap: .5rem; font-size: .85rem; cursor: pointer; }
.jsu-result { margin-top: 1rem; }
.os-spin { animation: jsu-spin 1s linear infinite; }
@keyframes jsu-spin { from { transform: rotate(0); } to { transform: rotate(360deg); } }
</style>
