<script setup>
// Partner-agreement notes editor.
//
// Each agreement is its own row in the iDempiere table CUST_Agreement_CBartner:
//   - DateFrom      → the date the agreement was made (date picker)
//   - Name          → short description / title of the agreement
//   - AgreementNote → the agreement content, authored as HTML in a WYSIWYG editor
//   - C_BPartner_ID → owner partner
//
// Self-contained: it loads and persists its own rows keyed by the partner id, so
// it does not participate in the partner form's save flow (mirrors
// PartnerReminderNotesEditor). Rows are ordered newest-first (DateFrom desc) and
// shown COLLAPSED as a one-line summary (date · name · note teaser); click to
// expand into the editor. Saving shows a toast and collapses the row.
import { DatePicker } from 'tedir-calendar'
import { date } from 'alga-js'
import { toast } from 'bulma-toast'

const { t } = useTranslation()

const props = defineProps({
  // The c_bpartner id these agreements belong 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 agreements = 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,
  dateFrom: r.DateFrom || r.dateFrom || '',
  name: r.Name || r.name || '',
  agreementNote: r.AgreementNote || r.agreementNote || '',
  saving: false,
  error: false,
  expanded: false   // loaded rows start collapsed (summary view)
})

const load = async () => {
  if(!hasPartner.value) {
    agreements.value = []
    loaded.value = true
    return
  }
  loading.value = true
  try {
    const res = await $fetch('/api/partners/agreements', {
      headers: useRequestHeaders(['cookie']),
      query: { bpartnerId: props.bpartnerId }
    })
    agreements.value = (res?.records || []).map(mapRecord)
  } catch(err) {
    console.error('Failed to load partner agreements', err)
    agreements.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() })

// Plain-text content of the HTML note (for the empty check + collapsed teaser).
const noteText = (html) => (html || '').replace(/<[^>]*>/g, ' ').replace(/&nbsp;/g, ' ').replace(/\s+/g, ' ').trim()
const hasContent = (item) => !!noteText(item.agreementNote) || !!(item.name || '').trim()

// "2026-06-10" → "10.06.2026" for the summary (falls back to raw value).
const formatDate = (val) => {
  const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(String(val || ''))
  return m ? `${m[3]}.${m[2]}.${m[1]}` : (val || '—')
}

// Persist a single agreement (create when no id yet, otherwise update).
// Returns true on success. Concurrent saves are coalesced.
const persist = async (item) => {
  if(props.readonly || !hasPartner.value) return false
  if(item.saving) { item._dirty = true; return false }

  item.saving = true
  item.error = false
  item._dirty = false
  let ok = false
  try {
    if(item.id) {
      await $fetch('/api/partners/agreements/update', {
        method: 'PUT',
        headers: useRequestHeaders(['cookie']),
        body: { id: item.id, dateFrom: item.dateFrom, name: item.name, agreementNote: item.agreementNote }
      })
    } else {
      const res = await $fetch('/api/partners/agreements/store', {
        method: 'POST',
        headers: useRequestHeaders(['cookie']),
        body: { bpartnerId: props.bpartnerId, dateFrom: item.dateFrom, name: item.name, agreementNote: item.agreementNote }
      })
      if(res?.id) item.id = res.id
    }
    ok = true
  } catch(err) {
    console.error('Failed to save partner agreement', err)
    item.error = true
  } finally {
    item.saving = false
    if(item._dirty) { return await persist(item) }
  }
  return ok
}

// Explicit save from the editor footer: persist → toast → collapse to summary.
const save = async (item) => {
  if(props.readonly) return
  if(!hasContent(item)) {
    toast({ message: t.value?.agreement_empty || 'Bitte Datum und Inhalt eingeben.', type: 'is-warning', duration: 2500, position: 'bottom-right' })
    return
  }
  const ok = await persist(item)
  if(ok) {
    toast({ message: t.value?.saved || 'Gespeichert', type: 'is-success', duration: 2000, position: 'bottom-right' })
    item.expanded = false
  } else {
    toast({ message: t.value?.save_error || 'Speichern fehlgeschlagen', type: 'is-danger', duration: 2500, position: 'bottom-right' })
  }
}

const expand = (item) => { item.expanded = true }

const addItem = () => {
  if(props.readonly || !hasPartner.value) return
  agreements.value.unshift({
    _key: ++keySeq,
    id: null,
    dateFrom: date.now('date'),   // default to today; the user can change it
    name: '',
    agreementNote: '',
    saving: false,
    error: false,
    expanded: true                // new rows open in edit mode
  })
}

// "Abbrechen": drop a never-saved empty row, otherwise just collapse.
const cancelEdit = (item, idx) => {
  if(!item.id) { agreements.value.splice(idx, 1); return }
  item.expanded = false
}

const removeItem = async (idx) => {
  if(props.readonly) return
  const item = agreements.value[idx]
  agreements.value.splice(idx, 1)
  if(item?.id) {
    try {
      await $fetch('/api/partners/agreements/destroy', {
        method: 'DELETE',
        headers: useRequestHeaders(['cookie']),
        body: { ids: [item.id] }
      })
      toast({ message: t.value?.deleted || 'Gelöscht', type: 'is-success', duration: 1800, position: 'bottom-right' })
    } catch(err) {
      console.error('Failed to delete partner agreement', err)
      agreements.value.splice(idx, 0, item)   // re-insert on failure
      toast({ message: t.value?.delete_error || 'Löschen fehlgeschlagen', type: 'is-danger', duration: 2500, position: 'bottom-right' })
    }
  }
}
</script>

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

    <template v-else>
      <div v-if="loading && !loaded" class="agreement-editor__loading">
        <i class="ti ti-loader-2 spin"></i>
        <span>{{ t.loading || 'Wird geladen…' }}</span>
      </div>

      <div v-else-if="!agreements.length" class="agreement-editor__empty">
        <i class="ti ti-notes-off"></i>
        <span>{{ t.no_agreements || 'Keine Vereinbarungen hinterlegt' }}</span>
      </div>

      <div v-else class="agreement-editor__list">
        <div
          v-for="(item, idx) in agreements"
          :key="item._key"
          class="agreement-editor__row"
          :class="{ 'has-error': item.error, 'is-collapsed': !item.expanded }"
        >
          <!-- ===== Collapsed one-line summary ===== -->
          <div v-if="!item.expanded" class="agreement-editor__summary" @click="expand(item)" :title="t.edit || 'Bearbeiten'">
            <span class="agreement-editor__bullet"><i class="ti ti-file-text"></i></span>
            <span class="agreement-editor__sum-date">{{ formatDate(item.dateFrom) }}</span>
            <span v-if="item.name" class="agreement-editor__sum-name">{{ item.name }}</span>
            <span class="agreement-editor__sum-teaser">{{ noteText(item.agreementNote) || '—' }}</span>
            <span class="agreement-editor__sum-actions">
              <button type="button" class="button is-small is-light" :title="t.edit || 'Bearbeiten'" @click.stop="expand(item)">
                <i class="ti ti-pencil"></i>
              </button>
              <button v-if="!readonly" type="button" class="button is-small is-danger is-outlined" :title="t.delete || 'Entfernen'" @click.stop="removeItem(idx)">
                <i class="ti ti-x"></i>
              </button>
            </span>
          </div>

          <!-- ===== Expanded editor ===== -->
          <div v-else class="agreement-editor__edit">
            <div class="agreement-editor__grid">
              <div class="agreement-editor__date">
                <label class="agreement-editor__field-label">{{ t.agreement_date || 'Datum der Vereinbarung' }}</label>
                <ClientOnly>
                  <DatePicker v-model="item.dateFrom" :placeholder="t.agreement_date || 'Datum'" />
                  <template #fallback>
                    <span class="agreement-editor__date-static">{{ formatDate(item.dateFrom) }}</span>
                  </template>
                </ClientOnly>
              </div>
              <div class="agreement-editor__name-field">
                <label class="agreement-editor__field-label">{{ t.agreement_name || 'Bezeichnung' }}</label>
                <input
                  type="text"
                  v-model="item.name"
                  class="input"
                  :readonly="readonly"
                  :placeholder="t.agreement_name_placeholder || 'Kurze Bezeichnung der Vereinbarung'"
                />
              </div>
            </div>

            <div class="agreement-editor__note-field">
              <label class="agreement-editor__field-label">{{ t.agreement_note_label || 'Inhalt' }}</label>
              <RichTextEditor
                v-model="item.agreementNote"
                :readonly="readonly"
                :placeholder="t.agreement_note_placeholder || 'Vereinbarung eintragen…'"
              />
            </div>

            <div v-if="!readonly" class="agreement-editor__foot">
              <button type="button" class="button is-small is-success" :class="{ 'is-loading': item.saving }" @click="save(item)">
                <i class="ti ti-check me-1"></i> {{ t.save || 'Speichern' }}
              </button>
              <button type="button" class="button is-small is-light" @click="cancelEdit(item, idx)">
                {{ t.cancel || 'Abbrechen' }}
              </button>
              <button type="button" class="button is-small is-danger is-outlined agreement-editor__del" :title="t.delete || 'Entfernen'" @click="removeItem(idx)">
                <i class="ti ti-trash"></i>
              </button>
            </div>
          </div>
        </div>
      </div>

      <button
        v-if="!readonly"
        type="button"
        class="button is-small is-info is-outlined agreement-editor__add"
        @click="addItem"
      >
        <i class="ti ti-plus me-1"></i>
        {{ t.new_agreement || 'Neue Vereinbarung' }}
      </button>
    </template>
  </div>
</template>

<style scoped>
.agreement-editor {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.agreement-editor__hint,
.agreement-editor__loading,
.agreement-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;
}
.agreement-editor__list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.agreement-editor__row {
  background: #fff;
  border: 1px solid #e3e7ec;
  border-left: 3px solid #10b981;
  border-radius: 0.45rem;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
}
.agreement-editor__row.has-error { border-left-color: #e53935; background: #fff7f7; }

/* ---- collapsed summary: everything on one line, teaser ellipsis-truncated ---- */
.agreement-editor__summary {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 0.6rem;
  cursor: pointer;
  min-width: 0;
}
.agreement-editor__summary:hover { background: #f6fdfa; border-radius: 0.45rem; }
.agreement-editor__bullet {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.55rem;
  height: 1.55rem;
  border-radius: 50%;
  background: #e7f8f1;
  color: #059669;
  flex-shrink: 0;
}
.agreement-editor__sum-date {
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: #334155;
  font-size: 0.9rem;
}
.agreement-editor__sum-name {
  flex-shrink: 0;
  max-width: 30%;
  font-weight: 600;
  color: #0f172a;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.agreement-editor__sum-name::before { content: '·'; margin-right: 0.55rem; color: #cbd5e1; }
.agreement-editor__sum-teaser {
  flex: 1 1 auto;
  min-width: 0;
  color: #64748b;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 0.9rem;
}
.agreement-editor__sum-actions {
  flex-shrink: 0;
  display: flex;
  gap: 0.25rem;
}
.agreement-editor__sum-actions .button { padding-left: 0.45rem; padding-right: 0.45rem; }

/* ---- expanded editor ---- */
.agreement-editor__edit {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 0.7rem 0.75rem;
}
.agreement-editor__grid {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}
.agreement-editor__date { flex: 0 0 auto; }
.agreement-editor__name-field { flex: 1 1 16rem; min-width: 12rem; }
.agreement-editor__field-label {
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: #6b7280;
  margin-bottom: 0.15rem;
}
.agreement-editor__date-static { font-size: 0.95rem; }
.agreement-editor__foot {
  display: flex;
  align-items: center;
  gap: 0.45rem;
}
.agreement-editor__del { margin-left: auto; }
.agreement-editor__add { align-self: flex-start; }
.is-readonly .agreement-editor__row { border-left-color: #c0c4cb; }
.spin { animation: agSpin 0.8s linear infinite; display: inline-block; }
@keyframes agSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
</style>
