<script setup>
import { computed, onMounted, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";

import BaseButton from "../../../components/base/BaseButton.vue";
import BaseCard from "../../../components/base/BaseCard.vue";
import BaseCheckbox from "../../../components/base/BaseCheckbox.vue";
import BaseDraggable from "../../../components/base/BaseDraggable.vue";
import BaseEditor from "../../../components/base/BaseEditor.vue";
import BaseIcon from "../../../components/base/BaseIcon.vue";
import BaseIndex from "../../../components/base/BaseIndex.vue";
import BaseInputNumber from "../../../components/base/BaseInputNumber.vue";
import BaseInputText from "../../../components/base/BaseInputText.vue";
import BaseModal from "../../../components/base/BaseModal.vue";
import BaseSelect from "../../../components/base/BaseSelect.vue";
import BaseStatusBadge from "../../../components/base/BaseStatusBadge.vue";
import { useBaseToast } from "../../../composables/useBaseToast.js";
import { api, ensureCsrf } from "../../../services/api.js";
import { useOffersApi } from "../composables/useOffersApi.js";

const route = useRoute();
const router = useRouter();
const toast = useBaseToast();

const {
  getOffer,
  updateOffer,
  sendOffer,
  editorMeta,
  downloadPdf,
  convertToProject,
  listCatalog,
} = useOffersApi();

const OFFER_STATUS_BADGES = {
  draft: {
    label: "Draft",
    class: "bg-surface-100 text-surface-600 dark:bg-surface-700 dark:text-surface-300",
  },
  sent: {
    label: "Sent",
    class: "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300",
  },
  won: {
    label: "Won",
    class: "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300",
  },
  lost: {
    label: "Lost",
    class: "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300",
  },
};

const offerId = computed(() => String(route.params.id ?? ""));
const model = ref(null);
const preview = ref(false);
const saving = ref(false);

const pricingOptions = [
  { label: "One-time", value: "one_time" },
  { label: "Weekly", value: "weekly" },
  { label: "Monthly", value: "monthly" },
  { label: "Hourly", value: "hourly" },
  { label: "Custom unit", value: "custom_unit" },
];

const discountOptions = [
  { label: "None", value: "none" },
  { label: "Percent", value: "percent" },
  { label: "Fixed", value: "fixed" },
];

const vatChoices = ref([21, 9, 0]);

const catalogDialog = ref(false);
const catalogRows = ref([]);
const catalogSearch = ref("");
const activePick = ref({ si: 0, ri: 0 });

const sendDialog = ref(false);
const sendChannels = ref({ link: true, pdf: false, email: false });
const emailTo = ref("");
const emailSubject = ref("");
const converting = ref(false);

const customerOptions = ref([]);
const contactOptions = ref([]);

let saveTimer = null;

function stampKeys(m) {
  (m?.sections ?? []).forEach((sec, si) => {
    sec._key ??= sec.id ?? `ns-${si}-${crypto.randomUUID()}`;
    (sec.rows ?? []).forEach((row, ri) => {
      row._key ??= row.id ?? `nr-${si}-${ri}-${crypto.randomUUID()}`;
    });
  });
}

function normalizePayload(src) {
  const m = structuredClone(src);
  m.sections = (m.sections ?? []).map((sec, si) => ({
    ...sec,
    title: sec.title ?? `Section ${si + 1}`,
    description_html: sec.description_html ?? "",
    sort_order: si,
    rows: (sec.rows ?? []).map((row, ri) => ({
      ...row,
      pricing_type: row.pricing_type ?? "one_time",
      discount_type: row.discount_type ?? "none",
      discount_value: Number(row.discount_value ?? 0),
      quantity: Number(row.quantity ?? 1),
      unit_price: Number(row.unit_price ?? 0),
      vat_rate: Number(row.vat_rate ?? 21),
      description_html: row.description_html ?? "<p></p>",
      custom_unit_label: row.custom_unit_label ?? "",
      sort_order: ri,
    })),
  }));
  stampKeys(m);
  return m;
}

function isEditable() {
  if (!model.value) return false;
  if (model.value.is_template) return true;
  return model.value.status === "draft";
}

function scheduleSave() {
  if (!isEditable()) return;
  if (saveTimer) clearTimeout(saveTimer);
  saveTimer = setTimeout(() => {
    saveTimer = null;
    persist();
  }, 700);
}

watch(
  () => (model.value ? JSON.stringify(model.value) : ""),
  () => { scheduleSave(); },
);

async function refresh() {
  const data = await getOffer(offerId.value);
  model.value = normalizePayload(data);
}

async function persist() {
  if (!model.value || !isEditable()) return;
  saving.value = true;
  try {
    const p = normalizePayload(model.value);
    const res = await updateOffer(offerId.value, {
      subject: p.subject,
      intro_html: p.intro_html,
      customer_id: p.customer_id ?? null,
      contact_id: p.contact_id ?? null,
      valid_until: p.valid_until || null,
      discount_type: p.discount_type ?? "none",
      discount_value: p.discount_value ?? 0,
      is_template: !!p.is_template,
      template_name: p.template_name ?? null,
      sections: p.sections.map((s) => ({
        title: s.title,
        description_html: s.description_html,
        sort_order: s.sort_order,
        rows: s.rows.map((r) => ({
          description_html: r.description_html,
          pricing_type: r.pricing_type,
          custom_unit_label: r.custom_unit_label || null,
          quantity: r.quantity,
          unit_price: r.unit_price,
          discount_type: r.discount_type,
          discount_value: r.discount_value,
          vat_rate: r.vat_rate,
          sort_order: r.sort_order,
          offer_service_catalog_item_id: r.offer_service_catalog_item_id ?? null,
        })),
      })),
    });
    model.value = normalizePayload(res);
  } finally {
    saving.value = false;
  }
}

function addSection() {
  model.value?.sections.push({
    title: `Section ${(model.value.sections.length || 0) + 1}`,
    description_html: "",
    rows: [],
  });
  stampKeys(model.value);
  scheduleSave();
}

function addRow(si) {
  const sec = model.value?.sections?.[si];
  if (!sec) return;
  sec.rows.push({
    description_html: "<p>Line item</p>",
    pricing_type: "one_time",
    quantity: 1,
    unit_price: 0,
    discount_type: "none",
    discount_value: 0,
    vat_rate: vatChoices.value[0] ?? 21,
    custom_unit_label: "",
  });
  stampKeys(model.value);
  scheduleSave();
}

function removeRow(si, ri) {
  model.value?.sections?.[si]?.rows?.splice(ri, 1);
  scheduleSave();
}

function removeSection(si) {
  model.value?.sections?.splice(si, 1);
  scheduleSave();
}

async function openCatalog(si, ri) {
  activePick.value = { si, ri };
  catalogSearch.value = "";
  await loadCatalog();
  catalogDialog.value = true;
}

async function loadCatalog() {
  const res = await listCatalog({
    search: catalogSearch.value || undefined,
    per_page: 80,
    include_inactive: false,
  });
  catalogRows.value = res?.data ?? [];
}

function applyCatalogItem(item) {
  const { si, ri } = activePick.value;
  const row = model.value.sections[si].rows[ri];
  const html = item.default_description?.trim()
    ? String(item.default_description)
    : `<p>${item.name}</p>`;
  row.description_html = html;
  row.pricing_type = item.default_pricing_type;
  row.unit_price = item.default_unit_price;
  row.quantity = item.default_quantity;
  row.vat_rate = item.default_vat_rate;
  row.custom_unit_label = item.default_custom_unit_label ?? "";
  row.offer_service_catalog_item_id = item.id;
  catalogDialog.value = false;
  scheduleSave();
}

const totals = computed(() => model.value?.totals ?? {});

const CUSTOMER_LIST_TOAST_KEY = "maestro.offers.customerListUnavailableToast";

async function loadCustomers() {
  try {
    await ensureCsrf();
    const { data } = await api.get("/api/customers", { params: { per_page: 100, sort_by: "name" } });
    customerOptions.value = (data?.data ?? []).map((c) => ({ label: c.name, value: c.id }));
    try {
      if (typeof sessionStorage !== "undefined") {
        sessionStorage.removeItem(CUSTOMER_LIST_TOAST_KEY);
      }
    } catch { /* ignore */ }
  } catch {
    customerOptions.value = [];
    try {
      if (typeof sessionStorage !== "undefined" && !sessionStorage.getItem(CUSTOMER_LIST_TOAST_KEY)) {
        sessionStorage.setItem(CUSTOMER_LIST_TOAST_KEY, "1");
        toast.warn(
          "You can still edit the offer. Enable the Customers module or fix permissions to pick a customer.",
          "Customer list unavailable",
          5000,
        );
      }
    } catch { /* sessionStorage unavailable */ }
  }
}

async function onCustomerChange() {
  contactOptions.value = [];
  if (!model.value?.customer_id) {
    model.value.contact_id = null;
    scheduleSave();
    return;
  }
  try {
    await ensureCsrf();
    const { data } = await api.get(`/api/customers/${model.value.customer_id}/contacts`);
    const contacts = data?.data ?? data ?? [];
    contactOptions.value = contacts.map((c) => ({
      label: `${c.first_name} ${c.last_name}`,
      value: c.id,
    }));
  } catch {
    contactOptions.value = [];
    toast.warn("Contacts could not be loaded", null, 3500);
  }
  scheduleSave();
}

async function onSend() {
  await persist();
  const channels = [];
  if (sendChannels.value.link) channels.push("link");
  if (sendChannels.value.pdf) channels.push("pdf");
  if (sendChannels.value.email) channels.push("email");
  try {
    const res = await sendOffer(offerId.value, {
      channels,
      email:
        sendChannels.value.email && emailTo.value
          ? { to: emailTo.value, subject: emailSubject.value || undefined }
          : undefined,
    });
    toast.success("Offer sent");
    if (res?.public_url) {
      await navigator.clipboard.writeText(res.public_url);
      toast.info("Public link copied to clipboard", null, 2200);
    }
    sendDialog.value = false;
    await refresh();
  } catch {
    toast.error("Send failed");
  }
}

async function onPdf() {
  const blob = await downloadPdf(offerId.value);
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = `offer-${model.value?.offer_number ?? offerId.value}.pdf`;
  a.click();
  URL.revokeObjectURL(url);
}

async function onConvert() {
  converting.value = true;
  try {
    await convertToProject(offerId.value, { name: model.value?.subject });
    toast.success("Project created from this offer");
    await refresh();
  } catch {
    toast.error("Conversion failed");
  } finally {
    converting.value = false;
  }
}

const vatOptions = computed(() =>
  vatChoices.value.map((x) => ({ label: `${x}%`, value: x })),
);

function rowTotal(row) {
  const qty = Number(row.quantity) || 0;
  const price = Number(row.unit_price) || 0;
  let sub = qty * price;
  if (row.discount_type === "percent") {
    sub -= sub * (Number(row.discount_value) || 0) / 100;
  } else if (row.discount_type === "fixed") {
    sub -= Number(row.discount_value) || 0;
  }
  return Math.max(0, sub);
}

const euroFmt = new Intl.NumberFormat("nl-NL", { style: "currency", currency: "EUR" });
function formatEuro(val) {
  return euroFmt.format(val ?? 0);
}

onMounted(async () => {
  try {
    const meta = await editorMeta();
    if (Array.isArray(meta?.vat_rate_presets)) {
      vatChoices.value = meta.vat_rate_presets.map((x) => Number(x));
    }
    await loadCustomers();
    await refresh();
    if (model.value?.customer_id) {
      await onCustomerChange();
    }
  } catch (e) {
    const detail = e?.response?.data?.message || e?.message || "";
    console.error("[OfferEditor] mount failed", e);
    toast.error(detail || "Could not load offer", "Error", 5000);
    router.push("/offers");
  }
});
</script>

<template>
  <BaseIndex v-if="model" flush hide-header>

    <!-- Header bar -->
    <div class="flex flex-wrap items-center justify-between gap-3 px-1 mb-5">
      <div class="flex items-center gap-3 min-w-0">
        <button
          type="button"
          class="inline-flex items-center justify-center w-8 h-8 rounded-lg text-surface-500 hover:text-surface-900 dark:hover:text-surface-0 hover:bg-surface-100 dark:hover:bg-surface-800 transition-colors shrink-0"
          @click="router.push('/offers')"
        >
          <BaseIcon name="arrow-left" />
        </button>
        <div class="flex items-center gap-2 min-w-0">
          <span class="font-semibold text-surface-900 dark:text-surface-0 text-lg truncate">
            {{ model.subject || model.offer_number }}
          </span>
          <span class="text-surface-400 text-sm font-mono shrink-0">{{ model.offer_number }}</span>
          <BaseStatusBadge :value="model.status" :value-map="OFFER_STATUS_BADGES" />
        </div>
        <span v-if="saving" class="text-xs text-surface-400 animate-pulse shrink-0">Saving…</span>
      </div>

      <div class="flex flex-wrap items-center gap-2">
        <button
          type="button"
          class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium border transition-colors"
          :class="preview
            ? 'bg-primary-50 border-primary-200 text-primary-700 dark:bg-primary-900/20 dark:border-primary-700 dark:text-primary-300'
            : 'bg-surface-50 border-surface-200 text-surface-600 hover:bg-surface-100 dark:bg-surface-800 dark:border-surface-700 dark:text-surface-300 dark:hover:bg-surface-700'"
          @click="preview = !preview"
        >
          <BaseIcon :name="preview ? 'eye-slash' : 'eye'" class="text-xs" />
          {{ preview ? "Edit" : "Preview" }}
        </button>

        <BaseButton
          v-if="model.status === 'draft' && !model.is_template"
          label="Send offer"
          icon="send"
          @click="sendDialog = true"
        />
        <BaseButton
          label="PDF"
          icon="download"
          variant="secondary"
          outlined
          @click="onPdf"
        />
        <BaseButton
          v-if="model.status === 'won' && !model.hour_project_id"
          label="Convert to project"
          icon="briefcase"
          variant="secondary"
          :loading="converting"
          @click="onConvert"
        />
      </div>
    </div>

    <!-- Two-column layout: document on the left, sidebar on the right -->
    <div class="grid gap-5 lg:grid-cols-[1fr_22rem] xl:grid-cols-[1fr_24rem] mb-5">

      <!-- Left: document content -->
      <div class="flex flex-col gap-4 min-w-0">

        <!-- Intro / preview -->
        <BaseCard>
          <div class="flex items-center justify-between mb-3">
            <h3 class="text-sm font-semibold text-surface-700 dark:text-surface-300 uppercase tracking-wide">
              Introduction
            </h3>
          </div>
          <div v-if="preview" class="prose dark:prose-invert max-w-none text-surface-800 dark:text-surface-50 min-h-[8rem]" v-html="model.intro_html ?? ''" />
          <BaseEditor
            v-else
            v-model="model.intro_html"
            :disabled="!isEditable()"
            editor-style="min-height: 180px"
            @update:model-value="scheduleSave"
          />
        </BaseCard>

        <!-- Sections -->
        <BaseDraggable
          v-model="model.sections"
          item-key="_key"
          handle=".drag-sec"
          :disabled="!isEditable() || preview"
          @end="scheduleSave"
        >
          <template #item="{ element: sec, index: si }">
            <BaseCard class="mb-4">
              <!-- Section header -->
              <div class="flex items-center gap-2 mb-4">
                <button
                  v-if="isEditable() && !preview"
                  type="button"
                  class="drag-sec cursor-grab text-surface-300 hover:text-surface-500 transition-colors"
                  title="Drag to reorder"
                >
                  <BaseIcon name="bars" />
                </button>
                <input
                  v-model="sec.title"
                  :disabled="preview || !isEditable()"
                  class="flex-1 bg-transparent border-0 border-b border-transparent focus:border-surface-300 dark:focus:border-surface-600 outline-none font-semibold text-surface-900 dark:text-surface-0 text-base py-0.5 transition-colors placeholder-surface-300"
                  placeholder="Section title"
                  @input="scheduleSave"
                />
                <button
                  v-if="isEditable() && !preview && model.sections.length > 1"
                  type="button"
                  class="text-surface-400 hover:text-red-500 transition-colors p-1 rounded"
                  title="Remove section"
                  @click="removeSection(si)"
                >
                  <BaseIcon name="trash" class="text-xs" />
                </button>
              </div>

              <!-- Line items -->
              <BaseDraggable
                v-model="sec.rows"
                item-key="_key"
                handle=".drag-row"
                :disabled="!isEditable() || preview"
                @end="scheduleSave"
              >
                <template #item="{ element: row, index: ri }">
                  <div class="border border-surface-100 dark:border-surface-800 rounded-xl bg-white dark:bg-surface-900 mb-2 overflow-hidden">

                    <!-- Description row -->
                    <div class="flex items-start gap-2 px-3 pt-3 pb-2">
                      <button
                        v-if="isEditable() && !preview"
                        type="button"
                        class="drag-row cursor-grab text-surface-300 hover:text-surface-500 transition-colors mt-2 shrink-0"
                        title="Drag to reorder"
                      >
                        <BaseIcon name="bars" class="text-xs" />
                      </button>
                      <div class="flex-1 min-w-0">
                        <div
                          v-if="preview"
                          class="prose prose-sm dark:prose-invert max-w-none min-h-[2rem] text-surface-800 dark:text-surface-100"
                          v-html="row.description_html"
                        />
                        <BaseEditor
                          v-else
                          v-model="row.description_html"
                          :disabled="!isEditable()"
                          :minimal="true"
                          editor-style="min-height: 56px"
                          @update:model-value="scheduleSave"
                        />
                      </div>
                      <button
                        v-if="isEditable() && !preview"
                        type="button"
                        class="text-surface-300 hover:text-red-500 transition-colors p-1 rounded shrink-0 mt-1.5"
                        title="Remove row"
                        @click="removeRow(si, ri)"
                      >
                        <BaseIcon name="trash" class="text-xs" />
                      </button>
                    </div>

                    <!-- Pricing strip -->
                    <div class="flex flex-wrap items-center gap-2 px-3 pb-3 border-t border-surface-50 dark:border-surface-800/60 pt-2">
                      <BaseSelect
                        v-if="!preview"
                        v-model="row.pricing_type"
                        :options="pricingOptions"
                        option-label="label"
                        option-value="value"
                        :show-clear="false"
                        :fluid="false"
                        class="w-28"
                        :disabled="!isEditable()"
                        @change="scheduleSave"
                      />
                      <span v-else class="text-xs text-surface-400 font-medium">
                        {{ pricingOptions.find(o => o.value === row.pricing_type)?.label }}
                      </span>
                      <BaseButton
                        v-if="isEditable() && !preview"
                        label="Catalog"
                        icon="search"
                        variant="secondary"
                        text
                        size="small"
                        @click="openCatalog(si, ri)"
                      />

                      <div class="flex-1" />

                      <!-- Qty × Price -->
                      <div class="flex items-center gap-1.5">
                        <BaseInputNumber
                          v-model="row.quantity"
                          :use-grouping="false"
                          :disabled="!isEditable() || preview"
                          placeholder="Qty"
                          class="w-16"
                          @update:model-value="scheduleSave"
                        />
                        <span class="text-surface-400 text-sm select-none shrink-0">×</span>
                        <BaseInputNumber
                          v-model="row.unit_price"
                          mode="decimal"
                          :use-grouping="false"
                          :max-fraction-digits="2"
                          :disabled="!isEditable() || preview"
                          placeholder="Unit price"
                          class="w-24"
                          @update:model-value="scheduleSave"
                        />
                      </div>

                      <!-- VAT -->
                      <BaseSelect
                        v-model="row.vat_rate"
                        :options="vatOptions"
                        option-label="label"
                        option-value="value"
                        :show-clear="false"
                        :fluid="false"
                        class="w-20"
                        :disabled="!isEditable() || preview"
                        placeholder="VAT"
                        @change="scheduleSave"
                      />

                      <!-- Custom unit label -->
                      <BaseInputText
                        v-if="row.pricing_type === 'custom_unit'"
                        v-model="row.custom_unit_label"
                        placeholder="Unit"
                        class="w-20"
                        :disabled="!isEditable() || preview"
                        @update:model-value="scheduleSave"
                      />

                      <!-- Inline discount (only when not none) -->
                      <template v-if="!preview">
                        <BaseSelect
                          v-model="row.discount_type"
                          :options="discountOptions"
                          option-label="label"
                          option-value="value"
                          :show-clear="false"
                          :fluid="false"
                          class="w-28"
                          :disabled="!isEditable()"
                          @change="scheduleSave"
                        />
                        <BaseInputNumber
                          v-if="row.discount_type !== 'none'"
                          v-model="row.discount_value"
                          :use-grouping="false"
                          :disabled="!isEditable()"
                          placeholder="Discount"
                          class="w-20"
                          @update:model-value="scheduleSave"
                        />
                      </template>

                      <!-- Line total -->
                      <div class="min-w-[6rem] text-right pl-2 shrink-0">
                        <span class="text-sm font-semibold text-surface-900 dark:text-surface-0 tabular-nums">
                          {{ formatEuro(rowTotal(row)) }}
                        </span>
                      </div>
                    </div>
                  </div>
                </template>
              </BaseDraggable>

              <BaseButton
                v-if="isEditable() && !preview"
                label="Add row"
                icon="plus"
                variant="secondary"
                outlined
                size="small"
                class="mt-1"
                @click="addRow(si)"
              />
            </BaseCard>
          </template>
        </BaseDraggable>

        <BaseButton
          v-if="isEditable() && !preview"
          label="Add section"
          icon="plus"
          variant="secondary"
          outlined
          fluid
          @click="addSection"
        />
      </div>

      <!-- Right: metadata sidebar -->
      <div class="flex flex-col gap-4">
        <BaseCard>
          <h3 class="text-sm font-semibold text-surface-700 dark:text-surface-300 uppercase tracking-wide mb-4">
            Offer details
          </h3>
          <div class="flex flex-col gap-4">
            <BaseInputText
              v-model="model.subject"
              label="Subject"
              :disabled="!isEditable()"
              @update:model-value="scheduleSave"
            />
            <BaseSelect
              v-model="model.customer_id"
              label="Customer"
              :options="customerOptions"
              option-label="label"
              option-value="value"
              placeholder="No customer"
              :disabled="!isEditable()"
              @change="onCustomerChange"
            />
            <BaseSelect
              v-model="model.contact_id"
              label="Contact"
              :options="contactOptions"
              option-label="label"
              option-value="value"
              placeholder="No contact"
              :disabled="!isEditable() || !model.customer_id"
              @change="scheduleSave"
            />
            <BaseInputText
              v-model="model.valid_until"
              label="Valid until"
              type="date"
              :disabled="!isEditable()"
              @change="scheduleSave"
            />
          </div>
        </BaseCard>

        <BaseCard>
          <h3 class="text-sm font-semibold text-surface-700 dark:text-surface-300 uppercase tracking-wide mb-4">
            Discount
          </h3>
          <div class="flex flex-col gap-4">
            <BaseSelect
              v-model="model.discount_type"
              label="Type"
              :options="discountOptions"
              option-label="label"
              option-value="value"
              :show-clear="false"
              :disabled="!isEditable()"
              @change="scheduleSave"
            />
            <BaseInputNumber
              v-if="model.discount_type !== 'none'"
              v-model="model.discount_value"
              label="Amount"
              :use-grouping="false"
              :disabled="!isEditable()"
              @update:model-value="scheduleSave"
            />
          </div>
        </BaseCard>

        <BaseCard>
          <h3 class="text-sm font-semibold text-surface-700 dark:text-surface-300 uppercase tracking-wide mb-4">
            Template
          </h3>
          <div class="flex flex-col gap-3">
            <BaseCheckbox
              v-model="model.is_template"
              binary
              label="Template library"
              :disabled="model.status !== 'draft'"
              @update:model-value="scheduleSave"
            />
            <BaseInputText
              v-if="model.is_template"
              v-model="model.template_name"
              label="Template name"
              @update:model-value="scheduleSave"
            />
          </div>
        </BaseCard>

        <!-- Totals -->
        <BaseCard class="bg-surface-50 dark:bg-surface-800/60">
          <h3 class="text-sm font-semibold text-surface-700 dark:text-surface-300 uppercase tracking-wide mb-4">
            Summary
          </h3>
          <dl class="flex flex-col gap-2 text-sm">
            <div class="flex justify-between">
              <dt class="text-surface-500">Subtotal</dt>
              <dd class="font-medium text-surface-900 dark:text-surface-0">{{ totals.lines_net_subtotal ?? "—" }}</dd>
            </div>
            <div class="flex justify-between">
              <dt class="text-surface-500">Discount</dt>
              <dd class="font-medium text-surface-900 dark:text-surface-0">{{ totals.offer_discount_amount ?? "—" }}</dd>
            </div>
            <div class="flex justify-between">
              <dt class="text-surface-500">Excl. VAT</dt>
              <dd class="font-medium text-surface-900 dark:text-surface-0">{{ totals.total_excl_vat ?? "—" }}</dd>
            </div>
            <div class="flex justify-between">
              <dt class="text-surface-500">VAT</dt>
              <dd class="font-medium text-surface-900 dark:text-surface-0">{{ totals.vat_total ?? "—" }}</dd>
            </div>
            <div class="flex justify-between pt-2 border-t border-surface-200 dark:border-surface-700 mt-1">
              <dt class="font-semibold text-surface-900 dark:text-surface-0 text-base">Total</dt>
              <dd class="font-bold text-surface-900 dark:text-surface-0 text-base">{{ totals.grand_total ?? "—" }}</dd>
            </div>
          </dl>
        </BaseCard>
      </div>
    </div>

    <!-- Catalog picker modal -->
    <BaseModal
      v-model:visible="catalogDialog"
      title="Pick from catalog"
      width="36rem"
      @show="loadCatalog"
    >
      <div class="flex gap-2 mb-4">
        <BaseInputText
          v-model="catalogSearch"
          placeholder="Search catalog…"
          class="flex-1"
          @keyup.enter="loadCatalog"
        />
        <BaseButton label="Search" icon="search" variant="secondary" @click="loadCatalog" />
      </div>
      <div class="max-h-72 overflow-auto flex flex-col gap-0.5">
        <button
          v-for="item in catalogRows"
          :key="item.id"
          type="button"
          class="flex items-start gap-3 w-full text-left px-3 py-2.5 rounded-lg hover:bg-surface-100 dark:hover:bg-surface-800 transition-colors"
          @click="applyCatalogItem(item)"
        >
          <div class="flex-1 min-w-0">
            <div class="font-medium text-surface-900 dark:text-surface-0 text-sm">{{ item.name }}</div>
            <div v-if="item.default_unit_price" class="text-xs text-surface-500 mt-0.5">
              {{ item.default_unit_price }} · {{ item.default_pricing_type }}
            </div>
          </div>
        </button>
        <p v-if="!catalogRows.length" class="text-center text-sm text-surface-400 py-6">No catalog items found.</p>
      </div>
    </BaseModal>

    <!-- Send offer modal -->
    <BaseModal
      v-model:visible="sendDialog"
      title="Send offer"
      width="32rem"
    >
      <div class="flex flex-col gap-4">
        <BaseCheckbox v-model="sendChannels.link" binary label="Copy public link after send" />
        <BaseCheckbox v-model="sendChannels.pdf" binary label="Expose PDF shortcut (requires login)" />
        <BaseCheckbox v-model="sendChannels.email" binary label="Send via email" />
        <template v-if="sendChannels.email">
          <BaseInputText v-model="emailTo" label="To" placeholder="recipient@example.com" />
          <BaseInputText v-model="emailSubject" label="Subject" placeholder="Your offer from …" />
        </template>
      </div>
      <template #footer-right>
        <BaseButton label="Cancel" variant="secondary" outlined @click="sendDialog = false" />
        <BaseButton label="Send" icon="send" @click="onSend" />
      </template>
    </BaseModal>

  </BaseIndex>
</template>
