<script setup>
// Invoice-creation reminder notes editor.
//
// Each reminder is now its own row in the iDempiere table
// CUST_InvoiceCreationNotes (one row per note), replacing the previous hack of
// packing the whole list into a single HTML text field on c_bpartner.
//   - Name        → optional subject
//   - Description → the note text
//   - NotesSequenceNumber → drag/arrow ordering
//   - C_BPartner_ID → owner partner
//
// The component is self-contained: it loads and persists its own rows keyed by
// the partner id, so it no longer participates in the partner form's save flow.
const props = defineProps({
  // The c_bpartner id this list of notes belongs to. Empty on a not-yet-saved
  // partner (create page) — the editor then shows a "save first" hint.
  bpartnerId: { type: [String, Number], default: '' },
  readonly: { type: Boolean, default: false }
})

const notes = ref([])
const loading = ref(false)
const loaded = ref(false)
let keySeq = 0

const hasPartner = computed(() => !!props.bpartnerId && String(props.bpartnerId).trim() !== '')

const mapRecord = (r) => ({
  _key: ++keySeq,
  id: r.id,
  name: r.Name || r.name || '',
  description: r.Description || r.description || '',
  sequence: Number(r.NotesSequenceNumber ?? r.notesSequenceNumber ?? 0),
  saving: false,
  error: false
})

const load = async () => {
  if(!hasPartner.value) {
    notes.value = []
    loaded.value = true
    return
  }
  loading.value = true
  try {
    const res = await $fetch('/api/partners/invoice-reminder-notes', {
      headers: useRequestHeaders(['cookie']),
      query: { bpartnerId: props.bpartnerId }
    })
    const records = (res?.records || []).map(mapRecord)
    // Keep server order (already by sequence), but be defensive.
    records.sort((a, b) => (a.sequence - b.sequence) || (a.id - b.id))
    notes.value = records
  } catch(err) {
    console.error('Failed to load invoice reminder notes', err)
    notes.value = []
  } finally {
    loading.value = false
    loaded.value = true
  }
}

onMounted(load)
// The partner id arrives after the parent's record fetch resolves.
watch(() => props.bpartnerId, () => { loaded.value = false; load() })

const nextSequence = () => {
  const max = notes.value.reduce((m, n) => Math.max(m, Number(n.sequence) || 0), 0)
  return max + 1
}

// Persist a single note. Creates it on first save (no id yet), otherwise updates.
// Concurrent saves for the same note are coalesced: blurring the subject then
// the description on a brand-new row must not fire two POSTs (which would create
// a duplicate). A save requested while one is in flight is re-run afterwards.
const persistNote = async (note) => {
  if(props.readonly || !hasPartner.value) return
  if(note.saving) { note._dirty = true; return }

  const name = (note.name || '').trim()
  const description = (note.description || '').trim()
  // Don't create an empty row in the DB; only persist once it has content.
  if(!note.id && !name && !description) return

  note.saving = true
  note.error = false
  note._dirty = false
  try {
    if(note.id) {
      await $fetch('/api/partners/invoice-reminder-notes/update', {
        method: 'PUT',
        headers: useRequestHeaders(['cookie']),
        body: { id: note.id, name, description, sequence: note.sequence }
      })
    } else {
      const res = await $fetch('/api/partners/invoice-reminder-notes/store', {
        method: 'POST',
        headers: useRequestHeaders(['cookie']),
        body: { bpartnerId: props.bpartnerId, name, description, sequence: note.sequence }
      })
      if(res?.id) note.id = res.id
    }
  } catch(err) {
    console.error('Failed to save invoice reminder note', err)
    note.error = true
  } finally {
    note.saving = false
    // A change arrived mid-save — flush it now (note.id is set by this point).
    if(note._dirty) { await persistNote(note) }
  }
}

const addItem = () => {
  if(props.readonly || !hasPartner.value) return
  notes.value.push({
    _key: ++keySeq,
    id: null,
    name: '',
    description: '',
    sequence: nextSequence(),
    saving: false,
    error: false
  })
  nextTick(() => {
    const inputs = document.querySelectorAll('.invoice-reminder-editor__note-input')
    const last = inputs[inputs.length - 1]
    if(last) last.focus()
  })
}

const removeItem = async (idx) => {
  if(props.readonly) return
  const note = notes.value[idx]
  notes.value.splice(idx, 1)
  if(note?.id) {
    try {
      await $fetch('/api/partners/invoice-reminder-notes/destroy', {
        method: 'DELETE',
        headers: useRequestHeaders(['cookie']),
        body: { ids: [note.id] }
      })
    } catch(err) {
      console.error('Failed to delete invoice reminder note', err)
      // Re-insert on failure so the UI reflects the real state.
      notes.value.splice(idx, 0, note)
    }
  }
}

// Renumber sequence to 1..n and persist any note whose number actually changed.
const renumberAndPersist = async () => {
  const changed = []
  notes.value.forEach((n, i) => {
    const seq = i + 1
    if(n.sequence !== seq) {
      n.sequence = seq
      if(n.id) changed.push(n)
    }
  })
  for(const n of changed) {
    await persistNote(n)
  }
}

const moveItem = async (idx, dir) => {
  if(props.readonly) return
  const j = idx + dir
  if(j < 0 || j >= notes.value.length) return
  const arr = notes.value
  const tmp = arr[idx]
  arr[idx] = arr[j]
  arr[j] = tmp
  await renumberAndPersist()
}
</script>

<template>
  <div class="invoice-reminder-editor" :class="{ 'is-readonly': readonly }">
    <!-- Partner not saved yet (create page) -->
    <div v-if="!hasPartner" class="invoice-reminder-editor__hint">
      <i class="ti ti-info-circle"></i>
      <span>Bitte speichern Sie den Partner zuerst, um Erinnerungen hinzuzufügen.</span>
    </div>

    <template v-else>
      <div v-if="loading && !loaded" class="invoice-reminder-editor__loading">
        <i class="ti ti-loader-2 spin"></i>
        <span>Erinnerungen werden geladen…</span>
      </div>

      <div v-else-if="!notes.length" class="invoice-reminder-editor__empty">
        <i class="ti ti-bell-off"></i>
        <span>Keine Erinnerungen hinterlegt</span>
      </div>

      <div v-else class="invoice-reminder-editor__list">
        <div
          v-for="(item, idx) in notes"
          :key="item._key"
          class="invoice-reminder-editor__row"
          :class="{ 'has-error': item.error }"
        >
          <span class="invoice-reminder-editor__bullet">
            <i class="ti ti-pin"></i>
          </span>
          <div class="invoice-reminder-editor__fields">
            <input
              type="text"
              v-model="item.name"
              class="input invoice-reminder-editor__subject"
              :readonly="readonly"
              placeholder="Betreff (optional)"
              @blur="persistNote(item)"
            />
            <textarea
              v-model="item.description"
              class="textarea invoice-reminder-editor__note-input"
              :readonly="readonly"
              rows="2"
              placeholder="Erinnerung eintragen..."
              @blur="persistNote(item)"
            ></textarea>
          </div>
          <span class="invoice-reminder-editor__status">
            <i v-if="item.saving" class="ti ti-loader-2 spin" title="Wird gespeichert…"></i>
            <i v-else-if="item.error" class="ti ti-alert-triangle has-text-danger" title="Speichern fehlgeschlagen"></i>
          </span>
          <div v-if="!readonly" class="invoice-reminder-editor__actions">
            <button
              type="button"
              class="button is-small is-light"
              :disabled="idx === 0"
              title="Nach oben"
              @click="moveItem(idx, -1)"
            >
              <i class="ti ti-arrow-up"></i>
            </button>
            <button
              type="button"
              class="button is-small is-light"
              :disabled="idx === notes.length - 1"
              title="Nach unten"
              @click="moveItem(idx, 1)"
            >
              <i class="ti ti-arrow-down"></i>
            </button>
            <button
              type="button"
              class="button is-small is-danger is-outlined"
              title="Entfernen"
              @click="removeItem(idx)"
            >
              <i class="ti ti-x"></i>
            </button>
          </div>
        </div>
      </div>

      <button
        v-if="!readonly"
        type="button"
        class="button is-small is-info is-outlined invoice-reminder-editor__add"
        @click="addItem"
      >
        <i class="ti ti-plus me-1"></i>
        Neue Erinnerung
      </button>
    </template>
  </div>
</template>

<style scoped>
.invoice-reminder-editor {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.invoice-reminder-editor__hint,
.invoice-reminder-editor__loading,
.invoice-reminder-editor__empty {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.85rem 1rem;
  border: 1px dashed #d3d8df;
  border-radius: 0.5rem;
  color: #6b7280;
  background: #fbfbfd;
  font-size: 0.9rem;
}
.invoice-reminder-editor__list {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}
.invoice-reminder-editor__row {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.55rem 0.6rem;
  background: #fff;
  border: 1px solid #e3e7ec;
  border-left: 3px solid #f5a623;
  border-radius: 0.4rem;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
}
.invoice-reminder-editor__row.has-error {
  border-left-color: #e53935;
  background: #fff7f7;
}
.invoice-reminder-editor__bullet {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  background: #fff5e6;
  color: #c97a00;
  flex-shrink: 0;
  margin-top: 0.15rem;
}
.invoice-reminder-editor__fields {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 0;
}
.invoice-reminder-editor__subject {
  border: none !important;
  box-shadow: none !important;
  padding: 0.2rem 0.45rem !important;
  background: transparent;
  font-size: 0.9rem;
  font-weight: 600;
  height: auto;
}
.invoice-reminder-editor__subject:focus {
  outline: none;
  background: #fffbf2;
}
.invoice-reminder-editor__note-input {
  border: none !important;
  box-shadow: none !important;
  padding: 0.25rem 0.45rem !important;
  background: transparent;
  font-size: 0.95rem;
  resize: vertical;
  min-height: 2.2rem;
}
.invoice-reminder-editor__note-input:focus {
  outline: none;
  background: #fffbf2;
}
.invoice-reminder-editor__status {
  width: 1.1rem;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 0.3rem;
  color: #c97a00;
}
.invoice-reminder-editor__actions {
  display: flex;
  gap: 0.25rem;
  flex-shrink: 0;
  margin-top: 0.1rem;
}
.invoice-reminder-editor__actions .button {
  padding-left: 0.45rem;
  padding-right: 0.45rem;
}
.invoice-reminder-editor__add {
  align-self: flex-start;
}
.is-readonly .invoice-reminder-editor__row {
  border-left-color: #c0c4cb;
}
.spin {
  animation: irnSpin 0.8s linear infinite;
  display: inline-block;
}
@keyframes irnSpin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
</style>
