<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch } from "vue";
import { apiDelete, apiGet, apiPost, apiPut } from "../api";
import FormStatus from "../components/FormStatus.vue";
import PageHeader from "../components/PageHeader.vue";
import SearchSelect from "../components/SearchSelect.vue";
import { decimalString, normalizeTaxRate, taxRateOptions } from "../format";
import { reserveNextNumber } from "../number-ranges";
import { liveUpdateState } from "../realtime";
import type { Activity, Customer, Item, OutgoingInvoice, OutgoingInvoiceItem, Quote } from "../types";

const emptyItem = (): OutgoingInvoiceItem => ({ line_kind: "item", item_id: "", activity_id: null, description: "", quantity: "1", unit_price: "0", original_unit_price: null, discount_percent: "0", tax_rate: "19" });
const emptyForm = () => ({ invoice_number: "", customer_id: "", status: "draft", cash_discount_term_id: null as string | null, customer_discount_percent: "0", issued_at: null as string | null, due_at: null as string | null, source_quote_id: null as string | null, items: [emptyItem()] });
const invoices = ref<OutgoingInvoice[]>([]);
const customers = ref<Customer[]>([]);
const items = ref<Item[]>([]);
const activities = ref<Activity[]>([]);
const quotes = ref<Quote[]>([]);
const selectedId = ref<string | null>(null);
const form = reactive(emptyForm());
const status = ref("");
const kind = ref<"info" | "success" | "error">("info");
const search = ref("");
const editingLineIndex = ref(0);
const customerName = (customerId: string) => customers.value.find((customer) => customer.id === customerId)?.name ?? customerId;
const filteredInvoices = computed(() => {
  const needle = search.value.trim().toLowerCase();
  if (!needle) return invoices.value;
  return invoices.value.filter((invoice) =>
    `${invoice.invoice_number} ${customerName(invoice.customer_id)} ${invoice.status}`.toLowerCase().includes(needle)
  );
});

async function load() {
  const [invoiceResult, customerResult, itemResult, quoteResult, activityResult] = await Promise.all([
    apiGet<OutgoingInvoice[]>("/api/v1/outgoing-invoices"), apiGet<Customer[]>("/api/v1/customers"), apiGet<Item[]>("/api/v1/items"), apiGet<Quote[]>("/api/v1/quotes"), apiGet<Activity[]>("/api/v1/activities")
  ]);
  if (invoiceResult.ok) invoices.value = invoiceResult.data; else { status.value = invoiceResult.message; kind.value = "error"; }
  if (customerResult.ok) customers.value = customerResult.data.filter((customer) => customer.status === "active");
  if (itemResult.ok) items.value = itemResult.data.filter((item) => item.status === "active");
  if (quoteResult.ok) quotes.value = quoteResult.data;
  if (activityResult.ok) activities.value = activityResult.data.filter((activity) => activity.status === "active");
}
async function createNew() { selectedId.value = null; Object.assign(form, emptyForm()); editingLineIndex.value = 0; form.invoice_number = (await reserveNextNumber("outgoing_invoices")) ?? ""; }
function select(invoice: OutgoingInvoice) { selectedId.value = invoice.id; Object.assign(form, { ...invoice, items: invoice.items.map((item) => ({ ...item, line_kind: item.line_kind ?? "item", tax_rate: normalizeTaxRate(item.tax_rate) })) }); editingLineIndex.value = 0; }
function addLine() { form.items.push(emptyItem()); editingLineIndex.value = form.items.length - 1; }
function removeLine(index: number) { if (form.items.length > 1) form.items.splice(index, 1); editingLineIndex.value = Math.min(editingLineIndex.value, form.items.length - 1); }
function applyItemDefaults(line: OutgoingInvoiceItem) {
  const item = items.value.find((record) => record.id === line.item_id);
  if (!item) return;
  line.description = item.name; line.unit_price = item.default_sales_price ?? "0"; line.original_unit_price = item.default_sales_price ?? null; line.tax_rate = normalizeTaxRate(item.tax_rate);
}
const lineSourceOptions = computed(() => [
  ...items.value.map((item) => ({ id: `item:${item.id}`, number: item.item_number, name: item.name })),
  ...activities.value.map((activity) => ({ id: `activity:${activity.id}`, number: activity.activity_number, name: activity.title }))
]);
function lineSourceValue(line: OutgoingInvoiceItem) {
  return line.line_kind === "activity" ? `activity:${line.activity_id ?? ""}` : `item:${line.item_id ?? ""}`;
}
function selectLineSource(line: OutgoingInvoiceItem, value: string | null) {
  if (!value) return;
  const [kind, id] = value.split(":");
  if (kind === "activity") {
    const activity = activities.value.find((record) => record.id === id);
    if (!activity) return;
    line.line_kind = "activity";
    line.activity_id = id;
    line.item_id = null;
    line.description = activity.title;
    line.unit_price = "0";
    line.original_unit_price = null;
    line.tax_rate = "19";
    return;
  }
  const item = items.value.find((record) => record.id === id);
  if (!item) return;
  line.line_kind = "item";
  line.item_id = id;
  line.activity_id = null;
  applyItemDefaults(line);
}
function applyCustomerDefaults(customerId: string | null) {
  if (!customerId) return;
  const customer = customers.value.find((record) => record.id === customerId);
  if (!customer) return;
  form.customer_discount_percent = customer.standard_discount_percent || "0";
  form.cash_discount_term_id = customer.cash_discount_term_id ?? null;
}
function lineName(line: OutgoingInvoiceItem) {
  if (line.line_kind === "activity") {
    const activity = activities.value.find((record) => record.id === line.activity_id);
    return activity ? `${activity.activity_number ?? "Aktivität"} - ${activity.title}` : "Keine Aktivität gewählt";
  }
  if (!line.item_id) return "Kein Artikel gewählt";
  const item = items.value.find((record) => record.id === line.item_id);
  return item ? `${item.item_number} - ${item.name}` : line.item_id;
}
function lineTotal(line: OutgoingInvoiceItem) {
  const quantity = Number(decimalString(line.quantity, "0"));
  const unitPrice = Number(decimalString(line.unit_price, "0"));
  const discount = Number(decimalString(line.discount_percent, "0"));
  const total = quantity * unitPrice * (1 - discount / 100);
  return Number.isFinite(total) ? total.toLocaleString("de-DE", { minimumFractionDigits: 2, maximumFractionDigits: 4 }) : "-";
}
async function save() {
  const payload = {
    ...form,
    customer_discount_percent: decimalString(form.customer_discount_percent),
    items: form.items.map((item) => ({
      ...item,
      line_kind: item.line_kind ?? "item",
      item_id: item.line_kind === "activity" ? null : item.item_id,
      activity_id: item.line_kind === "activity" ? item.activity_id : null,
      quantity: decimalString(item.quantity, "1"),
      unit_price: decimalString(item.unit_price),
      original_unit_price: item.original_unit_price === null ? null : decimalString(item.original_unit_price),
      discount_percent: decimalString(item.discount_percent),
      tax_rate: normalizeTaxRate(item.tax_rate)
    }))
  };
  const result = selectedId.value ? await apiPut<OutgoingInvoice>(`/api/v1/outgoing-invoices/${selectedId.value}`, payload) : await apiPost<OutgoingInvoice>("/api/v1/outgoing-invoices", payload);
  status.value = result.ok ? "Rechnung gespeichert." : result.message; kind.value = result.ok ? "success" : "error"; if (result.ok) { selectedId.value = result.data.id; await load(); }
}
async function finalize() { if (!selectedId.value) return; const result = await apiPost(`/api/v1/outgoing-invoices/${selectedId.value}/finalize`, {}); status.value = result.ok ? "Rechnung abgeschlossen." : result.message; kind.value = result.ok ? "success" : "error"; if (result.ok) await load(); }
async function cancelInvoice() { if (!selectedId.value) return; const result = await apiDelete(`/api/v1/outgoing-invoices/${selectedId.value}`); status.value = result.ok ? "Rechnung storniert." : result.message; kind.value = result.ok ? "success" : "error"; if (result.ok) await load(); }
async function convertQuote(quoteId: string) { const result = await apiPost<OutgoingInvoice>(`/api/v1/quotes/${quoteId}/convert-to-invoice`, {}); status.value = result.ok ? "Angebot umgewandelt." : result.message; kind.value = result.ok ? "success" : "error"; if (result.ok) { selectedId.value = result.data.id; await load(); } }
onMounted(load); watch(() => liveUpdateState.revision, load);
</script>
<template>
  <PageHeader title="Ausgangsrechnungen" description="Rechnungen erstellen, aus Angeboten übernehmen und abschließen." />
  <div class="workspace-split">
    <section class="panel list-panel"><div class="section-title"><h2>Rechnungen</h2><button type="button" @click="createNew">Neu</button></div>
      <label class="field list-search"><span>Suche</span><input v-model="search" type="search" placeholder="Rechnungsnummer, Kunde oder Status" /></label>
      <button v-for="invoice in filteredInvoices" :key="invoice.id" type="button" class="list-row" :class="{ selected: selectedId === invoice.id }" @click="select(invoice)"><strong>{{ invoice.invoice_number }}</strong><span>{{ customerName(invoice.customer_id) }}</span><small>{{ invoice.status }}</small></button>
      <p v-if="invoices.length === 0" class="empty">Keine Rechnungen vorhanden.</p>
      <p v-else-if="filteredInvoices.length === 0" class="empty">Keine Treffer.</p>
      <div class="sub-panel"><h2>Aus Angebot</h2><button v-for="quote in quotes" :key="quote.id" type="button" class="secondary" @click="convertQuote(quote.id)">{{ quote.quote_number }}</button></div>
    </section>
    <section class="panel detail-panel"><form @submit.prevent="save"><div class="form-grid">
      <label class="field"><span>Rechnungsnummer</span><div class="readonly-value">{{ form.invoice_number || "wird automatisch vergeben" }}</div></label>
      <label class="field"><span>Kunde</span><SearchSelect v-model="form.customer_id" :options="customers.map((customer) => ({ id: customer.id, number: customer.customer_number, name: customer.name }))" placeholder="Kunden-Nr. oder Name suchen" required @change="applyCustomerDefaults" /></label>
      <label class="field"><span>Status</span><select v-model="form.status"><option value="draft">Entwurf</option><option value="finalized">Abgeschlossen</option><option value="sent">Gesendet</option><option value="paid">Bezahlt</option><option value="cancelled">Storniert</option><option value="overdue">Überfällig</option></select></label>
      <label class="field"><span>Ausgestellt</span><input v-model="form.issued_at" type="date" /></label>
      <label class="field"><span>Fällig</span><input v-model="form.due_at" type="date" /></label>
      <label class="field"><span>Kundenrabatt %</span><input v-model="form.customer_discount_percent" inputmode="decimal" /></label>
    </div><div class="sub-panel"><div class="section-title"><h2>Positionen</h2></div><div class="position-table-header"><span>Position</span><span>Menge</span><span>Einzelpreis</span><span>Gesamtpreis</span><span>Steuer</span><span>Aktion</span></div>
      <div v-for="(line, index) in form.items" :key="index" class="quote-line">
        <template v-if="editingLineIndex !== index">
          <div class="position-summary">
            <strong>{{ lineName(line) }}</strong>
            <span>{{ line.quantity }}</span>
            <span>{{ line.unit_price }}</span>
            <span>{{ lineTotal(line) }}</span>
            <span>{{ line.tax_rate }} %</span>
          </div>
          <button type="button" class="secondary" @click="editingLineIndex = index">Bearbeiten</button>
        </template>
        <template v-else>
          <label class="field full-width"><span>Artikel oder Aktivität</span><SearchSelect :model-value="lineSourceValue(line)" :options="lineSourceOptions" placeholder="Artikel-/Aktivitäts-Nr. oder Name suchen" required @change="selectLineSource(line, $event)" /></label>
          <label class="field"><span>Menge</span><input v-model="line.quantity" inputmode="decimal" /></label><label class="field"><span>Preis</span><input v-model="line.unit_price" inputmode="decimal" /></label><label class="field"><span>Rabatt %</span><input v-model="line.discount_percent" inputmode="decimal" /></label><label class="field"><span>Steuer %</span><select v-model="line.tax_rate"><option v-for="rate in taxRateOptions" :key="rate" :value="rate">{{ rate }} %</option></select></label>
          <label class="field full-width"><span>Beschreibung</span><input v-model="line.description" /></label>
          <div class="position-actions"><button type="button" class="secondary" @click="removeLine(index)">Entfernen</button><button type="button" @click="addLine">Position hinzufügen</button></div>
        </template>
      </div></div><div class="form-actions"><button type="submit">Speichern</button><button v-if="selectedId" type="button" class="secondary" @click="finalize">Abschließen</button><button v-if="selectedId" type="button" class="secondary" @click="cancelInvoice">Stornieren</button></div><FormStatus :message="status" :kind="kind" /></form></section>
  </div>
</template>
