<script setup>
import dayjs from "dayjs"
import { Line } from "vue-chartjs"

const toast = useToast()
const tempStore = useTempStore()

const forecast = ref(null)
const rawForecast = ref(null)
const loading = ref(false)
const error = ref("")
const cacheLoaded = ref(false)

const CACHE_KEY = "fedeo:liquidityForecast:v3"

const dismissedRecurringKeys = computed(() => {
  return tempStore.settings?.liquidityForecast?.dismissedRecurringKeys || []
})

const includeDraftsAsInvoices = computed({
  get: () => Boolean(tempStore.settings?.liquidityForecast?.includeDraftsAsInvoices),
  set: (value) => {
    tempStore.modifySettings("liquidityForecast", {
      ...(tempStore.settings?.liquidityForecast || {}),
      includeDraftsAsInvoices: Boolean(value)
    })
  }
})

const storeDismissedRecurringKeys = (keys) => {
  tempStore.modifySettings("liquidityForecast", {
    ...(tempStore.settings?.liquidityForecast || {}),
    dismissedRecurringKeys: [...new Set(keys)].filter(Boolean)
  })
}

const sourceLabels = {
  open_createddocument: "Offene Ausgangsrechnung",
  open_incominginvoice: "Offener Eingangsbeleg",
  recurring_bankstatement: "Regelmäßige Bankbewegung",
  draft_createddocument: "Rechnungsentwurf",
  tax_settlement: "USt-Zahlung",
  serial_template: "Serienvorlage"
}

const intervalLabels = {
  weekly: "wöchentlich",
  monthly: "monatlich",
  quarterly: "quartalsweise",
  yearly: "jährlich"
}

const roundMoney = (value) => Number(Number(value || 0).toFixed(2))

const saveForecastCache = (value) => {
  if (!import.meta.client || !value) return
  localStorage.setItem(CACHE_KEY, JSON.stringify({
    cachedAt: new Date().toISOString(),
    forecast: value
  }))
}

const readForecastCache = () => {
  if (!import.meta.client) return null

  try {
    const raw = localStorage.getItem(CACHE_KEY)
    return raw ? JSON.parse(raw) : null
  } catch (err) {
    return null
  }
}

const applyForecastAdjustments = (value) => {
  if (!value) return null

  const dismissed = new Set(dismissedRecurringKeys.value)
  const baseEvents = (value.events || []).filter((event) => {
    return event.source !== "recurring_bankstatement" || !event.recurringKey || !dismissed.has(event.recurringKey)
  })
  const events = includeDraftsAsInvoices.value
    ? [...baseEvents, ...(value.draftEvents || [])]
    : baseEvents
  const recurring = (value.recurring || []).filter((item) => !item.key || !dismissed.has(item.key))
  const eventsByDate = new Map()

  events.forEach((event) => {
    if (!eventsByDate.has(event.date)) eventsByDate.set(event.date, [])
    eventsByDate.get(event.date).push(event)
  })

  let runningBalance = Number(value.startingBalance || 0)
  const points = (value.points || []).map((point) => {
    const dayEvents = [...(eventsByDate.get(point.date) || [])].sort((a, b) => Math.abs(b.amount) - Math.abs(a.amount))
    const income = roundMoney(dayEvents.filter((event) => event.amount > 0).reduce((sum, event) => sum + Number(event.amount || 0), 0))
    const expense = roundMoney(dayEvents.filter((event) => event.amount < 0).reduce((sum, event) => sum + Number(event.amount || 0), 0))

    runningBalance = roundMoney(runningBalance + income + expense)

    return {
      ...point,
      balance: runningBalance,
      income,
      expense,
      events: dayEvents
    }
  })

  const lowestPoint = points.reduce((lowest, point) => point.balance < lowest.balance ? point : lowest, points[0] || { balance: value.startingBalance, date: value.generatedAt })

  return {
    ...value,
    recurring,
    events,
    points,
    endingBalance: points[points.length - 1]?.balance || value.startingBalance,
    lowestBalance: lowestPoint?.balance || value.startingBalance,
    lowestBalanceDate: lowestPoint?.date || value.generatedAt,
    totalIncome: roundMoney(events.filter((event) => event.amount > 0).reduce((sum, event) => sum + Number(event.amount || 0), 0)),
    totalExpense: roundMoney(events.filter((event) => event.amount < 0).reduce((sum, event) => sum + Number(event.amount || 0), 0))
  }
}

const setRawForecast = (value) => {
  rawForecast.value = value
  forecast.value = applyForecastAdjustments(value)
}

const loadForecastFromCache = () => {
  const cached = readForecastCache()
  if (cached?.forecast) {
    setRawForecast({
      ...cached.forecast,
      cachedAt: cached.cachedAt
    })
  }

  cacheLoaded.value = true
}

const refreshForecast = async () => {
  loading.value = true
  error.value = ""

  try {
    const nextForecast = await useFunctions().useLiquidityForecast()
    saveForecastCache(nextForecast)
    setRawForecast({
      ...nextForecast,
      cachedAt: new Date().toISOString()
    })
    toast.add({
      title: "Prognose aktualisiert",
      description: "Das neue Ergebnis wurde zwischengespeichert.",
      color: "success"
    })
  } catch (err) {
    error.value = "Die Liquiditätsprognose konnte nicht neu erstellt werden."
    toast.add({
      title: "Fehler",
      description: error.value,
      color: "error"
    })
  } finally {
    loading.value = false
  }
}

const formatDate = (value) => dayjs(value).format("DD.MM.YYYY")

const getEventRoute = (event) => {
  if (event.source === "open_createddocument" && event.sourceId) return `/createDocument/show/${event.sourceId}`
  if (event.source === "open_incominginvoice" && event.sourceId) return `/incomingInvoices/show/${event.sourceId}`
  if (event.source === "tax_settlement") return "/accounting/tax"
  if (event.source === "serial_template" && event.sourceId) return `/createDocument/edit/${event.sourceId}`
  return null
}

const openEvent = (event) => {
  const route = getEventRoute(event)
  if (route) navigateTo(route)
}

const dismissRecurringKey = async (key) => {
  if (!key) return

  storeDismissedRecurringKeys([...dismissedRecurringKeys.value, key])
  forecast.value = applyForecastAdjustments(rawForecast.value)
  toast.add({
    title: "Bankbewegung abgeschlossen",
    description: "Das erkannte Muster wird aus der Liquiditätsprognose entfernt.",
    color: "success"
  })
}

const restoreDismissedRecurring = () => {
  storeDismissedRecurringKeys([])
  forecast.value = applyForecastAdjustments(rawForecast.value)
  toast.add({
    title: "Bankbewegungen wiederhergestellt",
    description: "Ausgeblendete Muster werden wieder in der Prognose berücksichtigt.",
    color: "success"
  })
}

const cachedAtLabel = computed(() => {
  const cachedAt = forecast.value?.cachedAt || forecast.value?.generatedAt
  return cachedAt ? formatDate(cachedAt) + " " + dayjs(cachedAt).format("HH:mm") : null
})

const chartData = computed(() => ({
  labels: (forecast.value?.points || []).map((point) => dayjs(point.date).format("DD.MM.")),
  datasets: [
    {
      label: "Prognostizierter Kontostand",
      borderColor: "#0f766e",
      backgroundColor: "rgba(15, 118, 110, 0.12)",
      pointRadius: 0,
      pointHitRadius: 8,
      tension: 0.28,
      fill: true,
      data: (forecast.value?.points || []).map((point) => point.balance)
    },
    {
      label: "Warnschwelle 0 €",
      borderColor: "#ef4444",
      borderDash: [6, 6],
      pointRadius: 0,
      data: (forecast.value?.points || []).map(() => 0)
    }
  ]
}))

const chartOptions = {
  responsive: true,
  maintainAspectRatio: false,
  interaction: {
    mode: "index",
    intersect: false
  },
  plugins: {
    legend: {
      display: true
    }
  },
  scales: {
    y: {
      ticks: {
        callback: (value) => useCurrency(Number(value))
      }
    }
  }
}

const upcomingEvents = computed(() => {
  return [...(forecast.value?.events || [])]
    .sort((a, b) => a.date.localeCompare(b.date) || Math.abs(b.amount) - Math.abs(a.amount))
    .slice(0, 18)
})

const groupedEventSummary = computed(() => {
  const summary = {
    open_createddocument: { label: sourceLabels.open_createddocument, amount: 0, count: 0 },
    open_incominginvoice: { label: sourceLabels.open_incominginvoice, amount: 0, count: 0 },
    recurring_bankstatement: { label: sourceLabels.recurring_bankstatement, amount: 0, count: 0 },
    draft_createddocument: { label: "Rechnungsentwürfe als Rechnungen", amount: 0, count: 0 },
    serial_template: { label: sourceLabels.serial_template, amount: 0, count: 0 },
    tax_settlement: { label: sourceLabels.tax_settlement, amount: 0, count: 0 }
  }

  ;(forecast.value?.events || []).forEach((event) => {
    if (!summary[event.source]) return
    summary[event.source].amount = roundMoney(summary[event.source].amount + Number(event.amount || 0))
    summary[event.source].count += 1
  })

  return Object.values(summary)
})

const topIncomeDrivers = computed(() => {
  return [...(forecast.value?.events || [])]
    .filter((event) => Number(event.amount || 0) > 0)
    .sort((a, b) => Number(b.amount || 0) - Number(a.amount || 0))
    .slice(0, 12)
})

const topExpenseDrivers = computed(() => {
  return [...(forecast.value?.events || [])]
    .filter((event) => Number(event.amount || 0) < 0)
    .sort((a, b) => Math.abs(Number(b.amount || 0)) - Math.abs(Number(a.amount || 0)))
    .slice(0, 12)
})

const draftIncomeDrivers = computed(() => {
  if (includeDraftsAsInvoices.value) return []

  return [...(forecast.value?.draftEvents || [])]
    .sort((a, b) => Number(b.amount || 0) - Number(a.amount || 0))
    .slice(0, 12)
})

const taxPeriodTypeLabel = computed(() => {
  if (forecast.value?.tax?.periodType === "quarterly") return "quartalsweise"
  if (forecast.value?.tax?.periodType === "yearly") return "jährlich"
  return "monatlich"
})

const taxForecastPeriods = computed(() => {
  return [...(forecast.value?.tax?.periods || [])]
    .filter((period) => Math.abs(Number(period.balance || 0)) > 0.01)
    .slice(0, 6)
})

const taxEventDrivers = computed(() => {
  return [...(forecast.value?.events || [])]
    .filter((event) => event.source === "tax_settlement")
    .sort((a, b) => a.date.localeCompare(b.date))
})

const detailedDays = computed(() => {
  let previousBalance = Number(forecast.value?.startingBalance || 0)

  return (forecast.value?.points || [])
    .filter((point) => (point.events || []).length > 0)
    .map((point) => {
      const startBalance = previousBalance
      previousBalance = Number(point.balance || 0)

      return {
        ...point,
        startBalance: roundMoney(startBalance)
      }
    })
    .slice(0, 24)
})

const riskTone = computed(() => {
  if (!forecast.value) return "neutral"
  if (forecast.value.lowestBalance < 0) return "danger"
  if (forecast.value.lowestBalance < forecast.value.startingBalance * 0.15) return "warning"
  return "positive"
})

watch(dismissedRecurringKeys, () => {
  forecast.value = applyForecastAdjustments(rawForecast.value)
})

watch(includeDraftsAsInvoices, () => {
  forecast.value = applyForecastAdjustments(rawForecast.value)
})

onMounted(() => {
  loadForecastFromCache()
})
</script>

<template>
  <UDashboardNavbar title="Liquiditätsprognose" />

  <UDashboardToolbar>
    <div class="flex w-full flex-wrap items-center justify-between gap-3">
      <div class="text-sm text-gray-500">
        <span v-if="cachedAtLabel">Zwischengespeichert am {{ cachedAtLabel }}</span>
        <span v-else>Noch keine gespeicherte Prognose vorhanden</span>
      </div>

      <div class="flex flex-wrap items-center gap-2">
        <div class="flex items-center gap-2 rounded-lg border border-gray-200 px-3 py-2 text-sm dark:border-gray-800">
          <USwitch v-model="includeDraftsAsInvoices" />
          <span class="text-gray-600 dark:text-gray-300">Entwürfe wie Rechnungen verwenden</span>
        </div>

        <UButton
          v-if="dismissedRecurringKeys.length"
          icon="i-heroicons-eye"
          variant="ghost"
          @click="restoreDismissedRecurring"
        >
          Ausgeblendete wiederherstellen
        </UButton>

        <UButton
          icon="i-heroicons-arrow-path"
          :loading="loading"
          variant="soft"
          @click="refreshForecast"
        >
          Prognose neu erstellen
        </UButton>
      </div>
    </div>
  </UDashboardToolbar>

  <UDashboardPanelContent class="min-w-0 space-y-6 overflow-x-hidden overflow-y-auto p-4 md:p-6">
    <UAlert
      v-if="error"
      color="error"
      icon="i-heroicons-exclamation-triangle"
      :title="error"
    />

    <div v-if="loading" class="flex min-h-[360px] items-center justify-center text-sm text-gray-500">
      Liquiditätsprognose wird erstellt...
    </div>

    <UCard v-else-if="cacheLoaded && !forecast">
      <div class="flex min-h-[280px] flex-col items-center justify-center gap-4 text-center">
        <UIcon name="i-heroicons-chart-bar-square" class="size-12 text-gray-300" />
        <div>
          <h2 class="text-lg font-semibold">Noch keine Prognose gespeichert</h2>
          <p class="mt-1 max-w-xl text-sm text-gray-500">
            Erstelle die Liquiditätsprognose bewusst über den Refresh-Button. Das Ergebnis bleibt danach zwischengespeichert und wird beim nächsten Öffnen sofort angezeigt.
          </p>
        </div>
        <UButton icon="i-heroicons-arrow-path" :loading="loading" @click="refreshForecast">
          Prognose neu erstellen
        </UButton>
      </div>
    </UCard>

    <template v-else-if="forecast">
      <div class="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
        <UCard>
          <p class="text-sm text-gray-500">Aktuelle Liquidität</p>
          <p class="mt-2 text-2xl font-semibold">{{ useCurrency(forecast.startingBalance) }}</p>
        </UCard>

        <UCard>
          <p class="text-sm text-gray-500">Prognose in {{ forecast.horizonDays }} Tagen</p>
          <p
            class="mt-2 text-2xl font-semibold"
            :class="forecast.endingBalance < 0 ? 'text-rose-600' : 'text-primary-600'"
          >
            {{ useCurrency(forecast.endingBalance) }}
          </p>
        </UCard>

        <UCard>
          <p class="text-sm text-gray-500">Niedrigster Stand</p>
          <p
            class="mt-2 text-2xl font-semibold"
            :class="forecast.lowestBalance < 0 ? 'text-rose-600' : 'text-orange-500'"
          >
            {{ useCurrency(forecast.lowestBalance) }}
          </p>
          <p class="mt-1 text-xs text-gray-500">{{ formatDate(forecast.lowestBalanceDate) }}</p>
        </UCard>

        <UCard>
          <p class="text-sm text-gray-500">KI-Erkennung</p>
          <p class="mt-2 text-2xl font-semibold">{{ forecast.recurring.length }}</p>
          <p class="mt-1 text-xs text-gray-500">
            {{ forecast.ai?.enabled ? `${forecast.ai.candidates} KI-Kandidaten berücksichtigt` : "Fallback ohne KI-Key genutzt" }}
          </p>
        </UCard>
      </div>

      <UAlert
        :color="riskTone === 'danger' ? 'error' : riskTone === 'warning' ? 'warning' : 'success'"
        :icon="riskTone === 'danger' ? 'i-heroicons-exclamation-triangle' : 'i-heroicons-chart-bar-square'"
        :title="riskTone === 'danger' ? 'Liquiditätsengpass möglich' : riskTone === 'warning' ? 'Liquidität wird knapp' : 'Liquidität bleibt positiv'"
        :description="`Die gespeicherte Prognose kombiniert aktuelle Kontostände, offene Belege und erkannte regelmäßige Bankbewegungen bis ${formatDate(dayjs().add(forecast.horizonDays, 'day'))}. Neu berechnet wird sie nur über den Refresh-Button.`"
      />

      <div class="grid gap-4 xl:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]">
        <UCard>
          <template #header>
            <div>
              <h2 class="font-semibold">Herleitung</h2>
              <p class="text-sm text-gray-500">So entsteht der prognostizierte Endstand</p>
            </div>
          </template>

          <div class="space-y-3">
            <div class="flex items-center justify-between gap-3">
              <span class="text-sm text-gray-500">Startbestand</span>
              <span class="font-semibold">{{ useCurrency(forecast.startingBalance) }}</span>
            </div>
            <div class="flex items-center justify-between gap-3">
              <span class="text-sm text-gray-500">Geplante Einzahlungen</span>
              <span class="font-semibold text-primary-600">+ {{ useCurrency(forecast.totalIncome) }}</span>
            </div>
            <div v-if="includeDraftsAsInvoices" class="flex items-center justify-between gap-3">
              <span class="text-sm text-gray-500">Davon aus Entwürfen</span>
              <span class="font-semibold text-primary-600">+ {{ useCurrency(rawForecast?.draftIncome || 0) }}</span>
            </div>
            <div v-else-if="forecast.draftIncome" class="flex items-center justify-between gap-3">
              <span class="text-sm text-gray-500">Rechnungsentwürfe optional</span>
              <span class="font-semibold text-gray-500">(+ {{ useCurrency(forecast.draftIncome) }})</span>
            </div>
            <div class="flex items-center justify-between gap-3">
              <span class="text-sm text-gray-500">Geplante Auszahlungen</span>
              <span class="font-semibold text-rose-600">{{ useCurrency(forecast.totalExpense) }}</span>
            </div>
            <div class="border-t border-dashed border-gray-200 pt-3 dark:border-gray-800">
              <div class="flex items-center justify-between gap-3">
                <span class="font-medium">Erwarteter Endstand</span>
                <span class="text-lg font-semibold">{{ useCurrency(forecast.endingBalance) }}</span>
              </div>
            </div>
          </div>
        </UCard>

        <UCard>
          <template #header>
            <div>
              <h2 class="font-semibold">Einflussfaktoren</h2>
              <p class="text-sm text-gray-500">Welche Quellen in die Prognose einfließen</p>
            </div>
          </template>

          <div class="divide-y divide-gray-200 dark:divide-gray-800">
            <div
              v-for="row in groupedEventSummary"
              :key="row.label"
              class="grid gap-3 py-3 sm:grid-cols-[minmax(0,1fr)_110px_140px]"
            >
              <div>
                <p class="font-medium">{{ row.label }}</p>
                <p class="text-xs text-gray-500">{{ row.count }} Positionen</p>
              </div>
              <span class="text-sm text-gray-500">{{ row.count }}x</span>
              <span
                class="text-right font-semibold"
                :class="row.amount < 0 ? 'text-rose-600' : row.amount > 0 ? 'text-primary-600' : 'text-gray-500'"
              >
                {{ useCurrency(row.amount) }}
              </span>
            </div>
          </div>
        </UCard>
      </div>

      <UCard v-if="taxForecastPeriods.length">
        <template #header>
          <div class="flex flex-wrap items-center justify-between gap-3">
            <div>
              <h2 class="font-semibold">USt in der Prognose</h2>
              <p class="text-sm text-gray-500">Aus der USt-Auswertung mit {{ taxPeriodTypeLabel }} Fälligkeit abgeleitet</p>
            </div>
            <UButton
              size="sm"
              variant="ghost"
              icon="i-heroicons-arrow-top-right-on-square"
              @click="navigateTo('/accounting/tax')"
            >
              USt-Auswertung öffnen
            </UButton>
          </div>
        </template>

        <div class="mb-4 rounded-lg border border-dashed border-gray-300 p-4 dark:border-gray-700">
          <div class="flex flex-wrap items-center justify-between gap-3">
            <div>
              <p class="text-sm text-gray-500">Im Prognosezeitraum berücksichtigte USt-Salden</p>
              <p class="text-xs text-gray-500">Positive Salden werden als Auszahlung an das Finanzamt eingeplant, negative als Erstattung.</p>
            </div>
            <span
              class="text-lg font-semibold"
              :class="Number(forecast.tax?.totalBalance || 0) > 0 ? 'text-rose-600' : 'text-primary-600'"
            >
              {{ useCurrency(Number(forecast.tax?.totalBalance || 0) * -1) }}
            </span>
          </div>
        </div>

        <div class="space-y-3">
          <div
            v-for="period in taxForecastPeriods"
            :key="period.key"
            class="grid gap-3 rounded-lg border border-gray-200 p-4 lg:grid-cols-[minmax(0,1.1fr)_minmax(0,1fr)_auto] dark:border-gray-800"
          >
            <div>
              <p class="font-medium">{{ period.label }}</p>
              <p class="text-xs text-gray-500">{{ period.range }} · Fällig am {{ formatDate(period.dueDate) }}</p>
            </div>
            <div class="grid gap-1 text-sm text-gray-500">
              <div class="flex items-center justify-between gap-3">
                <span>USt Rechnungen</span>
                <span>{{ useCurrency(period.outputTax) }}</span>
              </div>
              <div class="flex items-center justify-between gap-3">
                <span>Vorsteuer</span>
                <span>{{ useCurrency(period.inputTax) }}</span>
              </div>
              <div class="flex items-center justify-between gap-3 font-medium">
                <span>Saldo</span>
                <span :class="period.balance > 0 ? 'text-rose-600' : 'text-primary-600'">
                  {{ useCurrency(period.balance) }}
                </span>
              </div>
            </div>
            <div class="text-right">
              <p class="text-xs text-gray-500">{{ period.outputCount }} Ausgangsbelege · {{ period.inputCount }} Eingangsbelege</p>
              <p
                class="mt-2 text-lg font-semibold"
                :class="period.balance > 0 ? 'text-rose-600' : 'text-primary-600'"
              >
                {{ useCurrency(period.balance * -1) }}
              </p>
              <p class="text-xs text-gray-500">Liquiditätseffekt</p>
            </div>
          </div>
        </div>
      </UCard>

      <UCard v-if="draftIncomeDrivers.length">
        <template #header>
          <div>
            <h2 class="font-semibold">Rechnungsentwürfe in Klammern</h2>
            <p class="text-sm text-gray-500">Optionaler Einfluss, noch nicht im Endstand enthalten</p>
          </div>
        </template>

        <div class="mb-4 rounded-lg border border-dashed border-gray-300 p-4 dark:border-gray-700">
          <div class="flex items-center justify-between gap-3">
            <span class="text-sm text-gray-500">Optionale Zusatzliquidität aus Entwürfen</span>
            <span class="text-lg font-semibold text-gray-600">(+ {{ useCurrency(forecast.draftIncome) }})</span>
          </div>
        </div>

        <div class="space-y-2">
          <div
            v-for="event in draftIncomeDrivers"
            :key="`draft-${event.sourceId || event.label}-${event.date}`"
            class="grid gap-3 rounded-lg border border-gray-200 p-3 sm:grid-cols-[120px_minmax(0,1fr)_auto_auto] dark:border-gray-800"
          >
            <span class="text-sm text-gray-500">{{ formatDate(event.date) }}</span>
            <div class="min-w-0">
              <p class="truncate font-medium">{{ event.label }}</p>
              <p class="text-xs text-gray-500">Noch nicht gebucht · {{ sourceLabels[event.source] }}</p>
            </div>
            <span class="text-right font-semibold text-gray-600">(+ {{ useCurrency(event.amount) }})</span>
            <UButton
              v-if="getEventRoute(event)"
              size="xs"
              variant="ghost"
              icon="i-heroicons-arrow-top-right-on-square"
              @click="openEvent(event)"
            >
              Öffnen
            </UButton>
          </div>
        </div>
      </UCard>

      <UCard>
        <template #header>
          <div class="flex flex-wrap items-center justify-between gap-2">
            <div>
              <h2 class="font-semibold">Liquiditätsverlauf</h2>
              <p class="text-sm text-gray-500">Täglicher prognostizierter Kontostand</p>
            </div>
            <div class="flex gap-3 text-sm">
              <span class="text-primary-600">+ {{ useCurrency(forecast.totalIncome) }}</span>
              <span class="text-rose-600">{{ useCurrency(forecast.totalExpense) }}</span>
            </div>
          </div>
        </template>

        <div class="h-[360px]">
          <Line :data="chartData" :options="chartOptions" />
        </div>
      </UCard>

      <div class="grid gap-4 xl:grid-cols-2">
        <UCard>
          <template #header>
            <div>
              <h2 class="font-semibold">Größte Einflüsse</h2>
              <p class="text-sm text-gray-500">Die wichtigsten Treiber der Prognose</p>
            </div>
          </template>

          <div class="space-y-4">
            <div>
              <p class="mb-2 text-sm font-medium text-primary-700">Größte Einzahlungen</p>
              <div v-if="topIncomeDrivers.length" class="space-y-2">
                <div
                  v-for="event in topIncomeDrivers"
                  :key="`income-${event.source}-${event.sourceId || event.label}-${event.date}`"
                  class="flex items-center justify-between gap-3 rounded-lg border border-gray-200 p-3 dark:border-gray-800"
                >
                  <div class="min-w-0">
                    <p class="truncate font-medium">{{ event.label }}</p>
                    <p class="text-xs text-gray-500">{{ formatDate(event.date) }} · {{ sourceLabels[event.source] || event.source }}</p>
                  </div>
                  <span class="font-semibold text-primary-600">{{ useCurrency(event.amount) }}</span>
                </div>
              </div>
              <p v-else class="text-sm text-gray-500">Keine Einzahlungen im Prognosezeitraum.</p>
            </div>

            <div>
              <p class="mb-2 text-sm font-medium text-rose-700">Größte Auszahlungen</p>
              <div v-if="topExpenseDrivers.length" class="space-y-2">
                <div
                  v-for="event in topExpenseDrivers"
                  :key="`expense-${event.source}-${event.sourceId || event.label}-${event.date}`"
                  class="flex items-center justify-between gap-3 rounded-lg border border-gray-200 p-3 dark:border-gray-800"
                >
                  <div class="min-w-0">
                    <p class="truncate font-medium">{{ event.label }}</p>
                    <p class="text-xs text-gray-500">{{ formatDate(event.date) }} · {{ sourceLabels[event.source] || event.source }}</p>
                  </div>
                  <span class="font-semibold text-rose-600">{{ useCurrency(event.amount) }}</span>
                </div>
              </div>
            </div>
          </div>
        </UCard>

        <UCard>
          <template #header>
            <div>
              <h2 class="font-semibold">Tagesaufschlüsselung</h2>
              <p class="text-sm text-gray-500">Stand vor dem Tag, Bewegungen und neuer Stand</p>
            </div>
          </template>

          <div v-if="detailedDays.length" class="space-y-3">
            <div
              v-for="day in detailedDays"
              :key="day.date"
              class="rounded-xl border border-gray-200 p-4 dark:border-gray-800"
            >
              <div class="flex flex-wrap items-center justify-between gap-3">
                <div>
                  <p class="font-medium">{{ formatDate(day.date) }}</p>
                  <p class="text-xs text-gray-500">Start {{ useCurrency(day.startBalance) }} · Ende {{ useCurrency(day.balance) }}</p>
                </div>
                <div class="flex gap-3 text-sm">
                  <span class="text-primary-600">+ {{ useCurrency(day.income) }}</span>
                  <span class="text-rose-600">{{ useCurrency(day.expense) }}</span>
                </div>
              </div>

              <div class="mt-3 space-y-2">
                <div
                  v-for="event in day.events"
                  :key="`${day.date}-${event.source}-${event.sourceId || event.label}-${event.amount}`"
                  class="grid gap-3 sm:grid-cols-[minmax(0,1fr)_auto]"
                >
                  <div class="min-w-0">
                    <p class="truncate text-sm font-medium">{{ event.label }}</p>
                    <p class="text-xs text-gray-500">{{ sourceLabels[event.source] || event.source }}</p>
                  </div>
                  <span
                    class="text-right text-sm font-semibold"
                    :class="event.amount < 0 ? 'text-rose-600' : 'text-primary-600'"
                  >
                    {{ useCurrency(event.amount) }}
                  </span>
                </div>
              </div>
            </div>
          </div>

          <p v-else class="py-8 text-center text-sm text-gray-500">Keine einzelnen Tagesbewegungen im Prognosezeitraum vorhanden.</p>
        </UCard>
      </div>

      <UCard v-if="taxEventDrivers.length">
        <template #header>
          <div>
            <h2 class="font-semibold">Geplante USt-Zahlungen und Erstattungen</h2>
            <p class="text-sm text-gray-500">Direkt aus den berücksichtigten USt-Zeiträumen abgeleitet</p>
          </div>
        </template>

        <div class="space-y-2">
          <div
            v-for="event in taxEventDrivers"
            :key="`tax-${event.date}-${event.sourceId}`"
            class="grid gap-3 rounded-lg border border-gray-200 p-3 sm:grid-cols-[110px_minmax(0,1fr)_auto_auto] dark:border-gray-800"
          >
            <span class="text-sm text-gray-500">{{ formatDate(event.date) }}</span>
            <div class="min-w-0">
              <p class="truncate font-medium">{{ event.label }}</p>
              <p class="text-xs text-gray-500">{{ sourceLabels[event.source] }}</p>
            </div>
            <span
              class="text-right font-semibold"
              :class="event.amount < 0 ? 'text-rose-600' : 'text-primary-600'"
            >
              {{ useCurrency(event.amount) }}
            </span>
            <UButton
              size="xs"
              variant="ghost"
              icon="i-heroicons-arrow-top-right-on-square"
              @click="openEvent(event)"
            >
              Öffnen
            </UButton>
          </div>
        </div>
      </UCard>

      <div class="grid gap-4 xl:grid-cols-[minmax(0,1.2fr)_minmax(320px,0.8fr)]">
        <UCard>
          <template #header>
            <div>
              <h2 class="font-semibold">Nächste Zahlungsereignisse</h2>
              <p class="text-sm text-gray-500">Offene Belege und prognostizierte regelmäßige Bewegungen</p>
            </div>
          </template>

          <div v-if="upcomingEvents.length" class="divide-y divide-gray-200 dark:divide-gray-800">
            <div
              v-for="event in upcomingEvents"
              :key="`${event.source}-${event.sourceId || event.label}-${event.date}-${event.amount}`"
              class="grid gap-3 py-3 sm:grid-cols-[110px_minmax(0,1fr)_auto_auto]"
            >
              <span class="text-sm text-gray-500">{{ formatDate(event.date) }}</span>
              <div class="min-w-0">
                <p class="truncate font-medium">{{ event.label }}</p>
                <p class="text-xs text-gray-500">{{ sourceLabels[event.source] || event.source }}</p>
              </div>
              <span
                class="text-right font-semibold"
                :class="event.amount < 0 ? 'text-rose-600' : 'text-primary-600'"
              >
                {{ useCurrency(event.amount) }}
              </span>
              <div class="flex justify-end gap-1">
                <UButton
                  v-if="getEventRoute(event)"
                  size="xs"
                  variant="ghost"
                  icon="i-heroicons-arrow-top-right-on-square"
                  @click="openEvent(event)"
                >
                  Öffnen
                </UButton>
                <UButton
                  v-if="event.source === 'recurring_bankstatement' && event.recurringKey"
                  size="xs"
                  color="gray"
                  variant="ghost"
                  icon="i-heroicons-check-circle"
                  @click="dismissRecurringKey(event.recurringKey)"
                >
                  Abschließen
                </UButton>
              </div>
            </div>
          </div>

          <p v-else class="py-8 text-center text-sm text-gray-500">Keine Zahlungsereignisse im Prognosezeitraum erkannt.</p>
        </UCard>

        <UCard>
          <template #header>
            <div>
              <h2 class="font-semibold">Regelmäßige Bewegungen</h2>
              <p class="text-sm text-gray-500">Aus Bankumsätzen erkannt, inklusive KI-Analyse</p>
            </div>
          </template>

          <div v-if="forecast.recurring.length" class="space-y-3">
            <div
              v-for="item in forecast.recurring"
              :key="`${item.label}-${item.amount}-${item.nextDate}`"
              class="rounded-lg border border-gray-200 p-3 dark:border-gray-800"
            >
              <div class="flex items-start justify-between gap-3">
                <div class="min-w-0">
                  <p class="truncate font-medium">{{ item.label }}</p>
                  <p class="text-xs text-gray-500">
                    {{ intervalLabels[item.interval] || item.interval }} ab {{ formatDate(item.nextDate) }}
                  </p>
                </div>
                <span
                  class="text-right font-semibold"
                  :class="item.amount < 0 ? 'text-rose-600' : 'text-primary-600'"
                >
                  {{ useCurrency(item.amount) }}
                </span>
              </div>
              <div class="mt-2 flex flex-wrap items-center justify-between gap-2">
                <p class="text-xs text-gray-500">
                  Sicherheit {{ Math.round(item.confidence * 100) }}% · {{ item.evidence }}
                </p>
                <UButton
                  size="xs"
                  color="gray"
                  variant="soft"
                  icon="i-heroicons-check-circle"
                  @click="dismissRecurringKey(item.key)"
                >
                  Als abgeschlossen entfernen
                </UButton>
              </div>
            </div>
          </div>

          <p v-else class="py-8 text-center text-sm text-gray-500">Noch keine regelmäßigen Bewegungen erkannt.</p>
        </UCard>
      </div>
    </template>
  </UDashboardPanelContent>
</template>
