<script setup>
import { computed, onMounted, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import BaseButton from "../../../components/base/BaseButton.vue";
import BaseDatePicker from "../../../components/base/BaseDatePicker.vue";
import BaseInputText from "../../../components/base/BaseInputText.vue";
import BaseInputNumber from "../../../components/base/BaseInputNumber.vue";
import BaseModal from "../../../components/base/BaseModal.vue";
import BaseSelect from "../../../components/base/BaseSelect.vue";
import BaseTextarea from "../../../components/base/BaseTextarea.vue";
import CustomerForm from "../../customers/views/partials/CustomerForm.vue";
import { useCustomerForm } from "../../customers/composables/useCustomers.js";
import { useAuth } from "../../../composables/useAuth.js";
import { useBaseToast } from "../../../composables/useBaseToast.js";
import { formatDateYmd } from "../../../composables/useDataTableFilters.js";
import { api, ensureCsrf } from "../../../services/api.js";
import {
  bookInvoice,
  deleteInvoice,
  fetchInvoice,
  fetchInvoiceMeta,
  fetchInvoicePdfBlob,
  saveInvoiceDraft,
  sendInvoice,
  sendInvoiceCopy,
} from "../composables/useInvoices.js";

const route = useRoute();
const router = useRouter();
const toast = useBaseToast();
const { permissions } = useAuth();

const canEdit = computed(() => permissions.value.includes("invoices.edit"));
const canCreate = computed(() => permissions.value.includes("invoices.create"));
const canDelete = computed(() => permissions.value.includes("invoices.delete"));
const canSend = computed(() => permissions.value.includes("invoices.send"));
const canBook = computed(() => permissions.value.includes("invoices.book"));

const meta = ref({
  vat_rates: [],
  default_vat_rate_id: null,
  items_enabled: false,
  items: [],
});

const customerOptions = ref([]);
const loading = ref(true);
const saving = ref(false);
const invoice = ref(null);
const customerDialog = ref(false);
const customerDraft = ref({});
const { create: createCustomer, errors: customerErrors, saving: customerSaving } =
  useCustomerForm();

/** API dates: YYYY-MM-DD strings (BaseDatePicker single mode). */
const form = ref({
  type: "invoice",
  customer_id: null,
  credited_invoice_id: null,
  invoice_date: "",
  expiration_date: "",
  description: "",
  email_body: "",
  lines: [],
});

function addDaysYmd(ymd, n) {
  const m = String(ymd || "").match(/^(\d{4})-(\d{2})-(\d{2})$/);
  if (!m) return "";
  const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
  d.setDate(d.getDate() + n);
  return formatDateYmd(d);
}

function blankLine() {
  const vid = meta.value.default_vat_rate_id ?? meta.value.vat_rates?.[0]?.id;
  return {
    description: "",
    quantity: 1,
    unit_price_ex_vat: 0,
    vat_rate_id: vid,
    item_id: null,
  };
}

async function loadCustomers() {
  await ensureCsrf();
  const { data } = await api.get("/api/customers", {
    params: { per_page: 500, sort_by: "name", sort_dir: "asc" },
  });
  const rows = data.data ?? [];
  customerOptions.value = rows.map((c) => ({
    label: c.name,
    value: c.id,
    email: c.email,
  }));
}

async function loadMeta() {
  meta.value = await fetchInvoiceMeta();
}

function applyItemToLine(line, itemId) {
  const item = meta.value.items?.find((i) => i.id === itemId);
  if (!item) return;
  line.description = item.name || line.description;
  line.unit_price_ex_vat = Number(item.default_unit_price_ex_vat ?? 0);
  if (item.default_vat_rate_id) {
    line.vat_rate_id = item.default_vat_rate_id;
  }
}

const computedTotals = computed(() => {
  const sign = form.value.type === "credit_note" ? -1 : 1;
  let ex = 0;
  let vat = 0;
  for (const ln of form.value.lines ?? []) {
    const rateObj = meta.value.vat_rates?.find((r) => r.id === ln.vat_rate_id);
    const rate = Number(rateObj?.rate_percent ?? 0);
    const q = Number(ln.quantity ?? 0);
    const unit = Number(ln.unit_price_ex_vat ?? 0);
    const lineEx = Math.round(q * unit * 100) / 100;
    const lineVat = Math.round(lineEx * (rate / 100) * 100) / 100;
    ex += lineEx;
    vat += lineVat;
  }
  const inc = ex + vat;
  return {
    subtotal_ex_vat: sign * ex,
    total_vat: sign * vat,
    total_inc_vat: sign * inc,
  };
});

const isLocked = computed(() => invoice.value?.is_locked === true);

const itemSelectOptions = computed(() =>
  (meta.value.items ?? []).map((i) => ({
    label: i.name,
    value: i.id,
  })),
);

async function initNew() {
  const today = formatDateYmd(new Date());
  form.value.type =
    route.name === "invoices-credit-new" ? "credit_note" : "invoice";
  const cf = route.query.credit_for ? Number(route.query.credit_for) : null;
  form.value.credited_invoice_id = Number.isFinite(cf) ? cf : null;
  form.value.invoice_date = today;
  form.value.expiration_date = addDaysYmd(today, 30);
  form.value.lines = [blankLine()];
}

async function loadExisting(id) {
  const data = await fetchInvoice(id);
  invoice.value = data;
  form.value.type = data.type;
  form.value.customer_id = data.customer_id;
  form.value.credited_invoice_id = data.credited_invoice_id;
  form.value.invoice_date = data.invoice_date || "";
  form.value.expiration_date = data.expiration_date || "";
  form.value.description = data.description ?? "";
  form.value.email_body = data.email_body ?? "";
  form.value.lines =
    (data.lines ?? []).map((l) => ({
      id: l.id,
      description: l.description,
      quantity: l.quantity,
      unit_price_ex_vat: l.unit_price_ex_vat,
      vat_rate_id: l.vat_rate_id,
      item_id: l.item_id,
    })) || [];
  if (!form.value.lines.length) {
    form.value.lines = [blankLine()];
  }
}

async function boot() {
  loading.value = true;
  try {
    await loadMeta();
    await loadCustomers();
    if (route.name === "invoices-new" || route.name === "invoices-credit-new") {
      await initNew();
    } else if (route.params.id) {
      await loadExisting(route.params.id);
    }
  } catch (e) {
    toast.error(
      e?.response?.data?.message ?? "Onbekende fout",
      "Laden mislukt",
      5000,
    );
  } finally {
    loading.value = false;
  }
}

watch(
  () => route.params.id,
  async (id) => {
    if (!id) return;
    loading.value = true;
    try {
      await loadExisting(id);
    } finally {
      loading.value = false;
    }
  },
);

onMounted(boot);

function ymdForApi(v) {
  if (typeof v === "string" && /^\d{4}-\d{2}-\d{2}$/.test(v.trim())) {
    return v.trim();
  }
  if (v instanceof Date && !Number.isNaN(v.getTime())) {
    return formatDateYmd(v);
  }
  return "";
}

function buildPayload() {
  return {
    type: form.value.type,
    customer_id: form.value.customer_id,
    credited_invoice_id:
      form.value.type === "credit_note"
        ? form.value.credited_invoice_id
        : null,
    invoice_date: ymdForApi(form.value.invoice_date),
    expiration_date: ymdForApi(form.value.expiration_date),
    description: form.value.description || null,
    email_body: form.value.email_body || null,
    lines: form.value.lines.map((l) => ({
      description: l.description,
      quantity: l.quantity,
      unit_price_ex_vat: l.unit_price_ex_vat,
      vat_rate_id: l.vat_rate_id,
      item_id: l.item_id || null,
    })),
  };
}

async function onSaveDraft() {
  if (!canEdit.value && !canCreate.value) return;
  saving.value = true;
  try {
    const payload = buildPayload();
    const id = invoice.value?.id ?? route.params.id;
    const saved = await saveInvoiceDraft(payload, id ? Number(id) : null);
    invoice.value = saved;
    toast.success("Opgeslagen");
    if (!route.params.id && saved?.id) {
      await router.replace({
        name: "invoices-edit",
        params: { id: String(saved.id) },
      });
    }
  } catch (e) {
    toast.error(e?.response?.data?.message ?? "Opslaan mislukt", "Fout", 6000);
  } finally {
    saving.value = false;
  }
}

async function onSend() {
  if (!canSend.value) return;
  saving.value = true;
  try {
    await onSaveDraft();
    const id = invoice.value?.id ?? route.params.id;
    await sendInvoice(Number(id), {});
    toast.success("Verzonden", null, 4000);
    await boot();
  } catch (e) {
    toast.error(
      e?.response?.data?.message ?? "",
      "Verzenden mislukt",
      6000,
    );
  } finally {
    saving.value = false;
  }
}

async function onBook() {
  if (!canBook.value) return;
  saving.value = true;
  try {
    await onSaveDraft();
    const id = invoice.value?.id ?? route.params.id;
    await bookInvoice(Number(id));
    toast.success("Geboekt", null, 4000);
    await boot();
  } catch (e) {
    toast.error(e?.response?.data?.message ?? "", "Boeken mislukt", 6000);
  } finally {
    saving.value = false;
  }
}

async function onSendCopy() {
  if (!canSend.value) return;
  saving.value = true;
  try {
    const id = invoice.value?.id ?? route.params.id;
    await sendInvoiceCopy(Number(id), {});
    toast.success("Kopie verzonden", null, 4000);
  } catch (e) {
    toast.error(e?.response?.data?.message ?? "", "Mislukt", 6000);
  } finally {
    saving.value = false;
  }
}

async function onPdf() {
  try {
    const id = invoice.value?.id ?? route.params.id;
    const blob = await fetchInvoicePdfBlob(Number(id));
    const url = URL.createObjectURL(blob);
    window.open(url, "_blank", "noopener");
    setTimeout(() => URL.revokeObjectURL(url), 60_000);
  } catch {
    toast.error("PDF openen mislukt.");
  }
}

async function onDelete() {
  if (!canDelete.value) return;
  try {
    const id = invoice.value?.id ?? route.params.id;
    await deleteInvoice(Number(id));
    toast.success("Verwijderd");
    router.push({ name: "invoices" });
  } catch (e) {
    toast.error(e?.response?.data?.message ?? "", "Verwijderen mislukt", 6000);
  }
}

function openCustomerDialog() {
  customerDraft.value = {
    name: "",
    email: "",
    phone: "",
    website: "",
    notes: "",
    is_active: true,
  };
  customerDialog.value = true;
}

async function submitCustomer(payload) {
  try {
    const c = await createCustomer(payload);
    customerDialog.value = false;
    await loadCustomers();
    form.value.customer_id = c.id;
    toast.success("Klant aangemaakt");
  } catch {
    /* validation on CustomerForm */
  }
}

function addLine() {
  form.value.lines.push(blankLine());
}

function removeLine(i) {
  form.value.lines.splice(i, 1);
  if (!form.value.lines.length) {
    form.value.lines.push(blankLine());
  }
}

const vatSelectOptions = computed(() =>
  (meta.value.vat_rates ?? []).map((r) => ({
    label: `${r.label} (${r.rate_percent}%)${r.is_active === false ? " — inactief" : ""}`,
    value: r.id,
  })),
);
</script>

<template>
  <div class="p-4 md:p-6 max-w-6xl mx-auto">
    <div v-if="loading" class="text-surface-600">Laden…</div>

    <div v-else class="flex flex-col gap-6">
      <div class="flex flex-wrap items-center justify-between gap-3">
        <div>
          <h1 class="text-2xl font-semibold m-0">
            {{ form.type === "credit_note" ? "Creditnota" : "Factuur" }}
            <span
              v-if="invoice?.document_number"
              class="text-surface-500 text-lg font-normal"
            >
              {{ invoice.document_number }}
            </span>
          </h1>
          <p v-if="isLocked" class="text-amber-700 text-sm m-0 mt-1">
            Definitief — alleen PDF en kopiëren per e-mail mogelijk.
          </p>
        </div>
        <div class="flex flex-wrap gap-2">
          <BaseButton
            v-if="invoice?.type === 'invoice' && isLocked"
            variant="secondary"
            label="Nieuwe creditnota"
            @click="
              router.push({
                name: 'invoices-credit-new',
                query: { credit_for: String(invoice.id) },
              })
            "
          />
          <BaseButton
            v-if="invoice?.id"
            variant="secondary"
            icon="file"
            label="PDF"
            @click="onPdf"
          />
          <BaseButton
            v-if="isLocked && canSend"
            variant="secondary"
            label="E-mail kopie"
            @click="onSendCopy"
          />
          <BaseButton
            v-if="!isLocked && (canEdit || canCreate)"
            variant="primary"
            label="Concept opslaan"
            :loading="saving"
            @click="onSaveDraft"
          />
          <BaseButton
            v-if="!isLocked && canSend"
            variant="primary"
            label="Verzenden (e-mail)"
            :loading="saving"
            @click="onSend"
          />
          <BaseButton
            v-if="!isLocked && canBook"
            variant="secondary"
            label="Boeken (extern)"
            :loading="saving"
            @click="onBook"
          />
          <BaseButton
            v-if="!isLocked && canDelete && invoice?.id"
            variant="danger"
            label="Verwijderen"
            @click="onDelete"
          />
        </div>
      </div>

      <!-- Bewerkbare kop -->
      <div
        v-if="!isLocked"
        class="flex flex-col gap-4"
      >
        <div class="flex flex-col sm:flex-row gap-4 sm:items-end">
          <BaseSelect
            v-model="form.customer_id"
            class="flex-1 min-w-0"
            label="Klant"
            :options="customerOptions"
            option-label="label"
            option-value="value"
            placeholder="Kies klant"
            filter
            show-clear
          />
          <BaseButton
            variant="secondary"
            label="Nieuwe klant"
            class="shrink-0"
            @click="openCustomerDialog"
          />
        </div>

        <BaseInputText
          v-if="form.type === 'credit_note'"
          :model-value="
            form.credited_invoice_id != null
              ? String(form.credited_invoice_id)
              : ''
          "
          label="Gekoppelde factuur (ID)"
          placeholder="Factuur-ID"
          type="number"
          @update:model-value="
            (v) =>
              (form.credited_invoice_id =
                v !== '' && v != null ? Number(v) : null)
          "
        />

        <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
          <BaseDatePicker
            v-model="form.invoice_date"
            label="Factuurdatum"
          />
          <BaseDatePicker
            v-model="form.expiration_date"
            label="Vervaldatum"
          />
        </div>

        <BaseTextarea
          v-model="form.description"
          label="Omschrijving"
          :rows="3"
        />
      </div>

      <!-- Regels -->
      <div v-if="!isLocked" class="flex flex-col gap-4">
        <div class="flex flex-wrap items-center justify-between gap-3">
          <h2 class="text-lg font-semibold m-0">Regels</h2>
          <BaseButton
            variant="secondary"
            icon="plus"
            label="Regel toevoegen"
            size="small"
            @click="addLine"
          />
        </div>

        <div
          v-for="(line, idx) in form.lines"
          :key="idx"
          class="rounded-lg border border-surface-200 dark:border-surface-700 bg-surface-0 dark:bg-surface-950 p-4 space-y-4"
        >
          <div
            class="grid grid-cols-1 lg:grid-cols-12 gap-4 items-start"
          >
            <BaseSelect
              v-if="meta.items_enabled"
              class="lg:col-span-3 min-w-0"
              label="Artikel"
              :model-value="line.item_id"
              :options="itemSelectOptions"
              option-label="label"
              option-value="value"
              placeholder="—"
              show-clear
              @update:model-value="
                (v) => {
                  line.item_id = v;
                  if (v) applyItemToLine(line, v);
                }
              "
            />
            <BaseTextarea
              v-model="line.description"
              :class="[
                'min-w-0',
                meta.items_enabled ? 'lg:col-span-6' : 'lg:col-span-8',
              ]"
              label="Omschrijving"
              :rows="2"
            />
            <div
              class="flex justify-end lg:justify-end lg:col-span-3"
              :class="meta.items_enabled ? '' : 'lg:col-span-4'"
            >
              <BaseButton
                variant="danger"
                icon="trash"
                :iconOnly="true"
                text
                rounded
                size="small"
                aria-label="Regel verwijderen"
                @click="removeLine(idx)"
              />
            </div>

            <BaseInputNumber
              v-model="line.quantity"
              class="lg:col-span-2 min-w-0"
              label="Aantal"
              :min="0"
              :step="0.0001"
              :use-grouping="false"
            />
            <BaseInputNumber
              v-model="line.unit_price_ex_vat"
              class="lg:col-span-3 min-w-0"
              label="Prijs ex btw"
              mode="decimal"
              :min-fraction-digits="2"
              :max-fraction-digits="4"
              :use-grouping="false"
            />
            <BaseSelect
              v-model="line.vat_rate_id"
              class="lg:col-span-7 min-w-0"
              label="BTW"
              :options="vatSelectOptions"
              option-label="label"
              option-value="value"
              placeholder="—"
            />
          </div>
        </div>
      </div>

      <!-- Totalen (concept) -->
      <div
        v-if="!isLocked"
        class="border-t border-surface-200 dark:border-surface-700 pt-4 grid grid-cols-1 sm:grid-cols-3 gap-4 text-sm"
      >
        <div>
          <span class="text-surface-600">Ex btw:</span>
          <strong class="ml-2 tabular-nums">{{
            computedTotals.subtotal_ex_vat.toFixed(2)
          }}</strong>
        </div>
        <div>
          <span class="text-surface-600">BTW:</span>
          <strong class="ml-2 tabular-nums">{{
            computedTotals.total_vat.toFixed(2)
          }}</strong>
        </div>
        <div>
          <span class="text-surface-600">Incl. btw:</span>
          <strong class="ml-2 tabular-nums">{{
            computedTotals.total_inc_vat.toFixed(2)
          }}</strong>
        </div>
      </div>

      <!-- Definitief -->
      <div
        v-else-if="invoice"
        class="border-t border-surface-200 dark:border-surface-700 pt-4 flex flex-col gap-4 text-sm"
      >
        <p class="m-0">
          <strong>Klant:</strong>
          {{ invoice.customer?.name ?? "—" }}
        </p>
        <p class="m-0 whitespace-pre-wrap">
          <strong>Omschrijving:</strong>
          {{ invoice.description || "—" }}
        </p>
        <div class="overflow-x-auto rounded-lg border border-surface-200">
          <table class="w-full text-sm border-collapse min-w-[640px]">
            <thead>
              <tr class="bg-surface-50 dark:bg-surface-900">
                <th class="border border-surface-200 p-3 text-left font-medium">
                  Omschrijving
                </th>
                <th class="border border-surface-200 p-3 text-right font-medium">
                  Aantal
                </th>
                <th class="border border-surface-200 p-3 text-right font-medium">
                  Ex
                </th>
                <th class="border border-surface-200 p-3 text-right font-medium">
                  BTW
                </th>
                <th class="border border-surface-200 p-3 text-right font-medium">
                  Incl.
                </th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="ln in invoice.lines ?? []" :key="ln.id">
                <td class="border border-surface-200 p-3">{{ ln.description }}</td>
                <td class="border border-surface-200 p-3 text-right tabular-nums">
                  {{ ln.quantity }}
                </td>
                <td class="border border-surface-200 p-3 text-right tabular-nums">
                  {{ Number(ln.line_total_ex_vat).toFixed(2) }}
                </td>
                <td class="border border-surface-200 p-3 text-right tabular-nums">
                  {{ Number(ln.line_vat_amount).toFixed(2) }}
                </td>
                <td class="border border-surface-200 p-3 text-right tabular-nums">
                  {{ Number(ln.line_total_inc_vat).toFixed(2) }}
                </td>
              </tr>
            </tbody>
          </table>
        </div>
        <div
          class="grid grid-cols-1 sm:grid-cols-3 gap-4 font-medium tabular-nums"
        >
          <div>Ex btw: € {{ Number(invoice.subtotal_ex_vat).toFixed(2) }}</div>
          <div>BTW: € {{ Number(invoice.total_vat).toFixed(2) }}</div>
          <div>Incl.: € {{ Number(invoice.total_inc_vat).toFixed(2) }}</div>
        </div>
      </div>
    </div>

    <BaseModal
      v-model:visible="customerDialog"
      title="Nieuwe klant"
      width="32rem"
      class="max-w-lg"
    >
      <CustomerForm
        embedded
        :visible="customerDialog"
        :draft="customerDraft"
        :saving="customerSaving"
        :errors="customerErrors"
        title=""
        @submit="submitCustomer"
        @cancel="customerDialog = false"
      />
    </BaseModal>
  </div>
</template>
