<script setup>
import { parseDate } from "@internationalized/date"

const {$api, $dayjs} = useNuxtApp()
const toast = useToast()

defineShortcuts({
  '/': () => document.getElementById("searchinput").focus()
})

const tempStore = useTempStore()
const router = useRouter()
const route = useRoute()

const bankstatements = ref([])
const bankaccounts = ref([])
const customers = ref([])
const vendors = ref([])
const entitybankaccounts = ref([])
const createddocuments = ref([])
const incominginvoices = ref([])
const openDocuments = ref([])
const openIncomingInvoices = ref([])
const filterAccount = ref([])
const filterAccountInitialized = ref(false)
const isSyncing = ref(false)
const cashbookBookingModalOpen = ref(false)
const savingCashbookBooking = ref(false)
const loadingDocs = ref(true) // Startet im Ladezustand
const suggestionsModalOpen = ref(false)
const selectedSuggestionRowId = ref(null)

const CASHBOOK_BANK_ID = "fedeo-cashbook"

// Zeitraum-Optionen
const periodOptions = [
  {label: 'Aktueller Monat', key: 'current_month'},
  {label: 'Letzter Monat', key: 'last_month'},
  {label: 'Aktuelles Quartal', key: 'current_quarter'},
  {label: 'Letztes Quartal', key: 'last_quarter'},
  {label: 'Benutzerdefiniert', key: 'custom'}
]

const bankingFilterItems = [
  { label: 'Nur offene anzeigen', value: 'Nur offene anzeigen' },
  { label: 'Nur positive anzeigen', value: 'Nur positive anzeigen' },
  { label: 'Nur negative anzeigen', value: 'Nur negative anzeigen' }
]

// Initialisierungswerte
const selectedPeriod = ref(periodOptions[0].key)
const selectedPeriodOption = computed(() => {
  return periodOptions.find(period => period.key === selectedPeriod.value) || periodOptions[0]
})
const dateRange = ref({
  start: $dayjs().startOf('month').format('YYYY-MM-DD'),
  end: $dayjs().endOf('month').format('YYYY-MM-DD')
})

const cashbookForm = reactive({
  date: $dayjs().format("YYYY-MM-DD"),
  direction: "expense",
  amount: null
})

const getCalendarValue = (value) => {
  if (!value) return undefined

  const formatted = $dayjs(value).format('YYYY-MM-DD')
  return formatted ? parseDate(formatted) : undefined
}

const setDateRangeFromCalendar = (field, value) => {
  dateRange.value[field] = value ? value.toString() : ""
}

const getDateButtonLabel = (value) => value ? $dayjs(value).format('DD.MM.YYYY') : 'Kein Datum'

const setDateRangeFieldToToday = (field) => {
  dateRange.value[field] = $dayjs().format('YYYY-MM-DD')
}

const setupPage = async () => {
  loadingDocs.value = true
  try {
    const [statements, bankAccountItems, customerItems, vendorItems, entityBankItems, documentItems, invoiceItems] = await Promise.all([
      useEntities("bankstatements").select("*, statementallocations(*)", "valueDate", false),
      useEntities("bankaccounts").select(),
      useEntities("customers").select(),
      useEntities("vendors").select(),
      useEntities("entitybankaccounts").select(),
      useEntities("createddocuments").select("*, statementallocations(*), customer(id,name)"),
      useEntities("incominginvoices").select("*, statementallocations(*), vendor(*)")
    ])

    bankstatements.value = statements
    bankaccounts.value = (bankAccountItems || []).map((account) => ({
      ...account,
      displayLabel: getBankAccountLabel(account)
    }))
    customers.value = customerItems
    vendors.value = vendorItems
    entitybankaccounts.value = entityBankItems
    createddocuments.value = documentItems
    incominginvoices.value = invoiceItems.filter(i => i.state === "Gebucht")

    const documents = createddocuments.value.filter(i => i.type === "invoices" || i.type === "advanceInvoices")
    openDocuments.value = documents.filter(i => useSum().isOpenCreatedDocument(i, createddocuments.value))
        .map(i => ({
          ...i,
          docTotal: useSum().getCreatedDocumentSum(i, createddocuments.value),
          statementTotal: Number(i.statementallocations.reduce((n, {amount}) => n + amount, 0)),
          openSum: useSum().getCreatedDocumentOpenAmount(i, createddocuments.value).toFixed(2)
        }))

    openIncomingInvoices.value = invoiceItems
        .filter(i => i.state === "Gebucht" && !i.archived && i.statementallocations.reduce((n, {amount}) => n + amount, 0).toFixed(2) !== getInvoiceSum(i, false))

    const availableAccountIds = bankaccounts.value.map((account) => account.id)
    if (!filterAccountInitialized.value) {
      filterAccount.value = availableAccountIds
      filterAccountInitialized.value = true
    } else {
      filterAccount.value = filterAccount.value
          .map((account) => getBankAccountId(account))
          .filter((id) => availableAccountIds.includes(id))
    }

    // Erst nach dem Laden der Daten die Store-Werte anwenden
    const savedBanking = tempStore.settings?.['banking'] || {}
    if (savedBanking.periodKey) {
      const found = periodOptions.find(p => p.key === savedBanking.periodKey)
      if (found) selectedPeriod.value = found.key
    }
    if (savedBanking.range) {
      dateRange.value = savedBanking.range
    }
  } catch (err) {
    console.error("Setup Error:", err)
  } finally {
    loadingDocs.value = false
  }
}

// Watcher für Schnellwahlen & Persistenz
watch(selectedPeriod, (newPeriod, oldPeriod) => {
  const now = $dayjs()

  // Nur berechnen, wenn sich die Periode geändert hat
  if (newPeriod !== oldPeriod) {
    switch (newPeriod) {
      case 'current_month':
        dateRange.value = {start: now.startOf('month').format('YYYY-MM-DD'), end: now.endOf('month').format('YYYY-MM-DD')}
        break
      case 'last_month':
        const lastMonth = now.subtract(1, 'month')
        dateRange.value = {start: lastMonth.startOf('month').format('YYYY-MM-DD'), end: lastMonth.endOf('month').format('YYYY-MM-DD')}
        break
      case 'current_quarter':
        dateRange.value = {start: now.startOf('quarter').format('YYYY-MM-DD'), end: now.endOf('quarter').format('YYYY-MM-DD')}
        break
      case 'last_quarter':
        const lastQuarter = now.subtract(1, 'quarter')
        dateRange.value = {start: lastQuarter.startOf('quarter').format('YYYY-MM-DD'), end: lastQuarter.endOf('quarter').format('YYYY-MM-DD')}
        break
    }
  }
})

watch([selectedPeriod, dateRange], () => {
  tempStore.modifyBankingPeriod(selectedPeriod.value, dateRange.value)
}, { deep: true })

const syncBankStatements = async () => {
  isSyncing.value = true
  try {
    await $api('/api/functions/services/bankstatementsync', {method: 'POST'})
    toast.add({title: 'Erfolg', description: 'Bankdaten synchronisiert.', color: 'green'})
    await setupPage()
  } catch (error) {
    toast.add({title: 'Fehler', description: 'Fehler beim Abruf.', color: 'red'})
  } finally {
    isSyncing.value = false
  }
}

const templateColumns = [
  {key: "account", label: "Konto"},
  {key: "valueDate", label: "Valuta"},
  {key: "amount", label: "Betrag"},
  {key: "openAmount", label: "Offen"},
  {key: "partner", label: "Name"},
  {key: "text", label: "Beschreibung"}
]

const searchString = ref(tempStore.searchStrings["bankstatements"] || '')
const selectedFilters = ref(tempStore.filters?.["banking"]?.["main"] || ['Nur offene anzeigen'])

const shouldShowMonthDivider = (row, index) => {
  if (index === 0) return true;
  const prevRow = filteredRows.value[index - 1];
  return $dayjs(getStatementDate(row)).format('MMMM YYYY') !== $dayjs(getStatementDate(prevRow)).format('MMMM YYYY');
}

const calculateOpenSum = (statement) => {
  const allocated = statement.statementallocations?.reduce((acc, curr) => acc + curr.amount, 0) || 0;
  return (statement.amount - allocated).toFixed(2);
}

const getInvoiceSum = (invoice, onlyOpenSum) => {
  let sum = 0
  if (invoice.accounts) {
    invoice.accounts.forEach(account => {
      sum += (account.amountTax || 0)
      sum += (account.amountNet || 0)
    })
  }

  if (onlyOpenSum) sum = sum + Number(invoice.statementallocations.reduce((n, {amount}) => n + amount, 0))

  if (invoice.expense) {
    return (sum * -1).toFixed(2)
  } else {
    return sum.toFixed(2)
  }
}

const getStatementDate = (statement) => statement.valueDate || statement.date
const isCashbookAccount = (account) => account?.bankId === CASHBOOK_BANK_ID
const getBankAccountId = (account) => typeof account === "object" ? account?.id : account
const resolveBankAccount = (accountOrId) => {
  if (!accountOrId) return null
  if (typeof accountOrId === "object") return accountOrId
  return bankaccounts.value.find((account) => account.id === accountOrId) || null
}
const getBankAccountLabel = (account) => {
  if (!account) return ""
  if (isCashbookAccount(account)) return `${account.name || account.ownerName || "Kassenbuch"} - Konto ${account.datevNumber || account.iban}`
  return `${account.name || account.ownerName || "Bankkonto"} - ${account.iban}`
}
const selectedAccountLabel = computed(() => {
  if (filterAccount.value.length === 0) return "Keine Konten"
  if (filterAccount.value.length === bankaccounts.value.length) return "Alle Konten"
  if (filterAccount.value.length === 1) return getBankAccountLabel(resolveBankAccount(filterAccount.value[0]))
  return `${filterAccount.value.length} Konten`
})
const selectedCashbookAccount = computed(() => {
  if (filterAccount.value.length !== 1) return null
  const account = resolveBankAccount(filterAccount.value[0])
  return isCashbookAccount(account) ? account : null
})
const currentCashbookBalance = computed(() => {
  if (!selectedCashbookAccount.value) return 0
  const openingBalance = Number(selectedCashbookAccount.value.balance || 0)
  const movementSum = bankstatements.value
      .filter((statement) => statement.account === selectedCashbookAccount.value.id)
      .reduce((sum, statement) => sum + Number(statement.amount || 0), 0)
  return openingBalance + movementSum
})
const saveCashbookBooking = async () => {
  if (!selectedCashbookAccount.value || !cashbookForm.date || !cashbookForm.amount) {
    toast.add({ title: "Bitte Kasse, Datum und Betrag auswählen.", color: "warning" })
    return
  }

  savingCashbookBooking.value = true
  try {
    const created = await $api(`/api/banking/cashbooks/${selectedCashbookAccount.value.id}/bookings`, {
      method: "POST",
      body: {
        date: cashbookForm.date,
        direction: cashbookForm.direction,
        amount: Number(cashbookForm.amount)
      }
    })
    toast.add({ title: "Kassenbuchung erstellt." })
    cashbookForm.amount = null
    cashbookBookingModalOpen.value = false
    await router.push(`/banking/statements/edit/${created.statement.id}`)
  } finally {
    savingCashbookBooking.value = false
  }
}

const normalizeIban = (value) => String(value || "").replace(/\s+/g, "").toUpperCase()
const normalizeSuggestionText = (value) => String(value || "").toLowerCase().replace(/[^a-z0-9äöüß]+/gi, " ").replace(/\s+/g, " ").trim()
const getSuggestionTokens = (value) => [...new Set(normalizeSuggestionText(value).split(" ").filter((token) => token.length >= 4))]
const getMatchingPurposeParts = (value, candidates = []) => {
  const haystack = normalizeSuggestionText(value)
  if (!haystack) return []

  return [...new Set(
      candidates
          .flatMap(candidate => getSuggestionTokens(candidate))
          .filter(token => haystack.includes(token))
  )].slice(0, 3)
}

const getAmountMatchLabel = (openSum, remaining) => {
  const difference = Math.abs(Math.abs(Number(openSum)) - Math.abs(Number(remaining)))
  if (difference < 0.01) return "Betrag exakt"
  if (difference <= 1) return "Betrag fast passend"
  if (difference <= 5) return "Betrag ähnlich"
  return null
}

const isWithinAmountTolerance = (candidateSum, remaining) => {
  const reference = Math.abs(Number(remaining))
  const candidate = Math.abs(Number(candidateSum))
  if (!reference || !candidate) return false

  const difference = Math.abs(candidate - reference)
  return difference / reference <= 0.1
}

const resolveMatchedBankAccountId = (statement) => {
  const partnerIban = normalizeIban(statement.amount >= 0 ? (statement.debIban || statement.credIban) : (statement.credIban || statement.debIban))
  if (!partnerIban) return null
  return entitybankaccounts.value.find(account => normalizeIban(account.iban) === partnerIban)?.id || null
}

const getTopEntitySuggestion = (statement) => {
  const isCustomer = Number(statement.amount) >= 0
  const partnerName = normalizeSuggestionText(isCustomer ? (statement.debName || statement.credName) : (statement.credName || statement.debName))
  const partnerIban = normalizeIban(isCustomer ? (statement.debIban || statement.credIban) : (statement.credIban || statement.debIban))
  const matchedBankAccountId = resolveMatchedBankAccountId(statement)
  const sourceItems = isCustomer ? customers.value : vendors.value

  const suggestions = sourceItems.map(item => {
    const infoData = item.infoData || {}
    const bankAccountIds = Array.isArray(infoData.bankAccountIds) ? infoData.bankAccountIds.map(Number) : []
    const bankingIbans = Array.isArray(infoData.bankingIbans) ? infoData.bankingIbans.map(iban => normalizeIban(iban)) : []
    const normalizedEntityName = normalizeSuggestionText(item.name)
    const exactNameMatch = normalizedEntityName && partnerName && normalizedEntityName === partnerName
    const partialNameMatch = normalizedEntityName && partnerName
        ? normalizedEntityName.includes(partnerName) || partnerName.includes(normalizedEntityName)
        : false

    let score = 0
    let reason = ""

    if (matchedBankAccountId && bankAccountIds.includes(matchedBankAccountId) && partnerIban && bankingIbans.includes(partnerIban)) {
      score = 100
      reason = "IBAN und Bankkonto passen"
    } else if (matchedBankAccountId && bankAccountIds.includes(matchedBankAccountId)) {
      score = 95
      reason = "Bankkonto passt"
    } else if (partnerIban && bankingIbans.includes(partnerIban)) {
      score = 90
      reason = "IBAN bekannt"
    } else if (exactNameMatch) {
      score = 60
      reason = "Name passt"
    } else if (partialNameMatch) {
      score = 45
      reason = "Name ähnlich"
    }

    return {
      type: isCustomer ? "customer" : "vendor",
      id: item.id,
      name: item.name,
      number: isCustomer ? item.customerNumber : item.vendorNumber,
      score,
      reason
    }
  }).filter(item => item.score > 0)
    .sort((a, b) => b.score - a.score)

  return suggestions[0] || null
}

const getDocumentSuggestionMeta = (statement, document, suggestion) => {
  let score = 0
  const remaining = Math.abs(Number(calculateOpenSum(statement)))
  const openSum = Math.abs(Number(document.openSum))
  const purposeMatches = getMatchingPurposeParts(statement.text, [document.documentNumber, document.title, document.description])
  const amountLabel = getAmountMatchLabel(openSum, remaining)
  const withinTolerance = isWithinAmountTolerance(openSum, remaining)

  if (!withinTolerance) {
    return { score: 0, amountLabel: null, purposeMatches: [] }
  }

  if (openSum === remaining) score += 100
  else score += Math.max(0, 60 - Math.abs(openSum - remaining))

  if (suggestion && document.customer?.id === suggestion.id) score += 80
  if (purposeMatches.length > 0) score += 50 + (purposeMatches.length * 10)

  return { score, amountLabel, purposeMatches }
}

const getIncomingInvoiceSuggestionMeta = (statement, invoice, suggestion) => {
  let score = 0
  const remaining = Math.abs(Number(calculateOpenSum(statement)))
  const openSum = Math.abs(Number(getInvoiceSum(invoice, true)))
  const purposeMatches = getMatchingPurposeParts(statement.text, [invoice.reference, invoice.description])
  const amountLabel = getAmountMatchLabel(openSum, remaining)
  const withinTolerance = isWithinAmountTolerance(openSum, remaining)

  if (!withinTolerance) {
    return { score: 0, amountLabel: null, purposeMatches: [] }
  }

  if (openSum === remaining) score += 100
  else score += Math.max(0, 60 - Math.abs(openSum - remaining))

  if (suggestion && invoice.vendor?.id === suggestion.id) score += 80
  if (purposeMatches.length > 0) score += 50 + (purposeMatches.length * 10)

  return { score, amountLabel, purposeMatches }
}

const getRowSuggestions = (statement) => {
  const entitySuggestion = getTopEntitySuggestion(statement)

  const topDocument = (entitySuggestion?.type === "customer" ? openDocuments.value.filter(doc => doc.customer?.id === entitySuggestion.id) : openDocuments.value)
      .map(document => {
        const meta = getDocumentSuggestionMeta(statement, document, entitySuggestion?.type === "customer" ? entitySuggestion : null)
        return { ...document, suggestionScore: meta.score, suggestionAmountLabel: meta.amountLabel, suggestionPurposeMatches: meta.purposeMatches, suggestionKey: `document:${document.id}` }
      })
      .filter(document => !isSuggestionDismissed(statement.id, document.suggestionKey))
      .filter(document => document.suggestionScore >= 80 || document.suggestionPurposeMatches?.length > 0)
      .sort((a, b) => b.suggestionScore - a.suggestionScore)[0] || null

  const topIncomingInvoice = (entitySuggestion?.type === "vendor" ? openIncomingInvoices.value.filter(invoice => invoice.vendor?.id === entitySuggestion.id) : openIncomingInvoices.value)
      .map(invoice => {
        const meta = getIncomingInvoiceSuggestionMeta(statement, invoice, entitySuggestion?.type === "vendor" ? entitySuggestion : null)
        return { ...invoice, suggestionScore: meta.score, suggestionAmountLabel: meta.amountLabel, suggestionPurposeMatches: meta.purposeMatches, suggestionKey: `invoice:${invoice.id}` }
      })
      .filter(invoice => !isSuggestionDismissed(statement.id, invoice.suggestionKey))
      .filter(invoice => invoice.suggestionScore >= 80 || invoice.suggestionPurposeMatches?.length > 0)
      .sort((a, b) => b.suggestionScore - a.suggestionScore)[0] || null

  return {
    topDocument,
    topIncomingInvoice
  }
}

const rowSuggestions = computed(() => {
  const entries = filteredRows.value.map(row => [row.id, getRowSuggestions(row)])
  return Object.fromEntries(entries)
})

const dismissedSuggestions = computed(() => tempStore.settings?.banking?.dismissedSuggestions || {})

const getDismissedSuggestionKeys = (statementId) => {
  const key = String(statementId || "")
  const values = dismissedSuggestions.value?.[key]
  return Array.isArray(values) ? values : []
}

const isSuggestionDismissed = (statementId, suggestionKey) => {
  return getDismissedSuggestionKeys(statementId).includes(suggestionKey)
}

const rowsWithSuggestions = computed(() => {
  return filteredRows.value
      .map((row) => ({
        row,
        suggestions: rowSuggestions.value[row.id]
      }))
      .filter(({ suggestions }) => suggestions?.topDocument || suggestions?.topIncomingInvoice)
})

const suggestionCount = computed(() => rowsWithSuggestions.value.length)

const selectedSuggestionRow = computed(() => {
  return rowsWithSuggestions.value.find((entry) => entry.row.id === selectedSuggestionRowId.value) || rowsWithSuggestions.value[0] || null
})

const filteredRows = computed(() => {
  if (!bankstatements.value.length) return []

  let temp = [...bankstatements.value]

  // Filterung nach Datum
  if (dateRange.value.start) {
    temp = temp.filter(i => $dayjs(getStatementDate(i)).isSameOrAfter($dayjs(dateRange.value.start), 'day'))
  }
  if (dateRange.value.end) {
    temp = temp.filter(i => $dayjs(getStatementDate(i)).isSameOrBefore($dayjs(dateRange.value.end), 'day'))
  }

  // Status Filter
  if (selectedFilters.value.includes("Nur offene anzeigen")) {
    temp = temp.filter(i => Number(calculateOpenSum(i)) !== 0)
  }
  if (selectedFilters.value.includes("Nur positive anzeigen")) {
    temp = temp.filter(i => i.amount >= 0)
  }
  if (selectedFilters.value.includes("Nur negative anzeigen")) {
    temp = temp.filter(i => i.amount < 0)
  }

  // Konto Filter & Suche
  let results = temp.filter(i => filterAccount.value.find(x => getBankAccountId(x) === i.account))

  if (searchString.value) {
    results = useSearch(searchString.value, results)
  }

  return results.sort((a, b) => $dayjs(getStatementDate(b)).unix() - $dayjs(getStatementDate(a)).unix())
})

const displayCurrency = (value) => `${Number(value).toFixed(2).replace(".", ",")} €`

const saveAllocation = async (allocation) => {
  await $api("/api/banking/statements", {
    method: "POST",
    body: { data: allocation }
  })
  await setupPage()
}

const handleAssignDocument = async (row, document, event) => {
  event.stopPropagation()
  await saveAllocation({
    createddocument: document.id,
    bankstatement: row.id,
    amount: Number(Number(document.openSum) < Number(calculateOpenSum(row)) ? document.openSum : calculateOpenSum(row)),
    description: "Automatischer Vorschlag"
  })
}

const handleAssignIncomingInvoice = async (row, invoice, event) => {
  event.stopPropagation()
  await saveAllocation({
    incominginvoice: invoice.id,
    bankstatement: row.id,
    amount: Number(Math.abs(getInvoiceSum(invoice, true)) > Math.abs(Number(calculateOpenSum(row))) ? calculateOpenSum(row) : getInvoiceSum(invoice, true)),
    description: "Automatischer Vorschlag"
  })
}

const dismissSuggestion = (row, suggestionKey, event) => {
  event.stopPropagation()
  const bankingSettings = tempStore.settings?.banking || {}
  const dismissed = { ...(bankingSettings.dismissedSuggestions || {}) }
  const rowKey = String(row.id || "")
  const existing = Array.isArray(dismissed[rowKey]) ? dismissed[rowKey] : []
  if (!existing.includes(suggestionKey)) dismissed[rowKey] = [...existing, suggestionKey]

  tempStore.modifySettings("banking", {
    ...bankingSettings,
    dismissedSuggestions: dismissed
  })

  if (selectedSuggestionRowId.value === row.id) {
    const remaining = getDismissedSuggestionKeys(row.id).concat([suggestionKey])
    const current = rowSuggestions.value[row.id]
    const noMoreSuggestions = (!current?.topDocument || remaining.includes(current.topDocument.suggestionKey))
      && (!current?.topIncomingInvoice || remaining.includes(current.topIncomingInvoice.suggestionKey))

    if (noMoreSuggestions) {
      const nextRow = rowsWithSuggestions.value.find((entry) => entry.row.id !== row.id)
      selectedSuggestionRowId.value = nextRow?.row.id || null
    }
  }
}

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

<template>
  <UDashboardNavbar title="Bankbuchungen" :badge="filteredRows.length">
    <template #right>
      <UButton
          v-if="selectedCashbookAccount"
          color="primary"
          variant="solid"
          icon="i-heroicons-plus"
          @click="cashbookBookingModalOpen = true"
      >
        Eintrag hinzufügen
      </UButton>
      <UButton
          color="primary"
          variant="soft"
          icon="i-heroicons-sparkles"
          @click="suggestionsModalOpen = true"
      >
        Vorschläge
        <UBadge color="primary" variant="solid" size="xs" class="ml-2">{{ suggestionCount }}</UBadge>
      </UButton>
      <UButton
          label="Bankabruf"
          icon="i-heroicons-arrow-path"
          :loading="isSyncing"
          @click="syncBankStatements"
          class="mr-2"
      />
      <UInput
          id="searchinput"
          v-model="searchString"
          icon="i-heroicons-magnifying-glass"
          placeholder="Suche..."
          @change="tempStore.modifySearchString('bankstatements',searchString)"
      />
    </template>
  </UDashboardNavbar>

  <UDashboardToolbar>
    <template #left>
      <div class="flex items-center gap-3">
        <USelectMenu
            :items="bankaccounts"
            v-model="filterAccount"
            value-key="id"
            label-key="displayLabel"
            multiple
            placeholder="Konten"
            class="w-64"
        >
          <template #default>
            {{ selectedAccountLabel }}
          </template>
        </USelectMenu>
        <USeparator orientation="vertical" class="h-6"/>
        <div class="flex items-center gap-2">
          <USelectMenu
              v-model="selectedPeriod"
              :items="periodOptions"
              value-key="key"
              label-key="label"
              class="w-44"
              icon="i-heroicons-calendar-days"
          >
            <template #default>
              {{ selectedPeriodOption.label || 'Zeitraum' }}
            </template>
          </USelectMenu>
          <div v-if="selectedPeriod === 'custom'" class="flex items-center gap-1">
            <div class="flex items-center gap-1">
              <UPopover class="w-full" :content="{ side: 'bottom', align: 'start' }">
                <UButton
                    block
                    color="neutral"
                    variant="outline"
                    class="w-36 justify-start"
                    icon="i-heroicons-calendar"
                    :label="getDateButtonLabel(dateRange.start)"
                />

                <template #content>
                  <div class="p-2">
                    <UCalendar
                      :model-value="getCalendarValue(dateRange.start)"
                      @update:model-value="setDateRangeFromCalendar('start', $event)"
                      :week-starts-on="1"
                    />
                  </div>
                </template>
              </UPopover>
            </div>
            <div class="flex items-center gap-1">
              <UPopover class="w-full" :content="{ side: 'bottom', align: 'start' }">
                <UButton
                    block
                    color="neutral"
                    variant="outline"
                    class="w-36 justify-start"
                    icon="i-heroicons-calendar"
                    :label="getDateButtonLabel(dateRange.end)"
                />

                <template #content>
                  <div class="p-2">
                    <UCalendar
                      :model-value="getCalendarValue(dateRange.end)"
                      @update:model-value="setDateRangeFromCalendar('end', $event)"
                      :week-starts-on="1"
                    />
                  </div>
                </template>
              </UPopover>
            </div>
          </div>
          <div v-else class="text-xs text-gray-400 hidden sm:block italic">
            {{ $dayjs(dateRange.start).format('DD.MM.') }} - {{ $dayjs(dateRange.end).format('DD.MM.YYYY') }}
          </div>
        </div>
      </div>
    </template>

    <template #right>
      <USelectMenu
          icon="i-heroicons-adjustments-horizontal"
          multiple
          v-model="selectedFilters"
          :items="bankingFilterItems"
          value-key="value"
          label-key="label"
          @update:model-value="tempStore.modifyFilter('banking','main',selectedFilters)"
      >
        <template #default>
          Filter
        </template>
      </USelectMenu>
    </template>
  </UDashboardToolbar>

  <div class="overflow-y-auto relative" style="height: calc(100vh - 200px)">
    <div v-if="loadingDocs" class="p-20 flex flex-col items-center justify-center">
      <UProgress animation="carousel" class="w-1/3 mb-4" />
      <span class="text-sm text-gray-500 italic">Bankbuchungen werden geladen...</span>
    </div>

    <table v-else class="w-full text-left border-collapse">
      <thead class="sticky top-0 bg-white dark:bg-gray-900 z-10 shadow-sm">
      <tr class="text-xs font-semibold text-gray-500 uppercase">
        <th v-for="col in templateColumns" :key="col.key" class="p-4 border-b dark:border-gray-800">
          {{ col.label }}
        </th>
      </tr>
      </thead>
      <tbody>
      <template v-for="(row, index) in filteredRows" :key="row.id">
        <tr v-if="shouldShowMonthDivider(row, index)">
          <td colspan="6" class="bg-gray-50 dark:bg-gray-800/50 p-2 pl-4 text-sm font-bold text-primary-600 border-y dark:border-gray-800">
            <div class="flex items-center gap-2">
              <UIcon name="i-heroicons-calendar" class="w-4 h-4"/>
              {{ $dayjs(getStatementDate(row)).format('MMMM YYYY') }}
            </div>
          </td>
        </tr>
        <tr
            class="hover:bg-gray-50 dark:hover:bg-gray-800/30 cursor-pointer border-b dark:border-gray-800 text-sm group"
            @click="router.push(`/banking/statements/edit/${row.id}`)"
        >
          <td class="p-4 text-[10px] text-gray-400 font-mono truncate max-w-[150px]">
            {{ row.account ? getBankAccountLabel(bankaccounts.find(i => i.id === row.account)) : "" }}
          </td>
          <td class="p-4 whitespace-nowrap">{{ $dayjs(getStatementDate(row)).format("DD.MM.YY") }}</td>
          <td class="p-4 font-semibold">
              <span :class="row.amount >= 0 ? 'text-green-600 dark:text-green-400' : 'text-rose-600 dark:text-rose-400'">
                {{ displayCurrency(row.amount) }}
              </span>
          </td>
          <td class="p-4 text-gray-400 italic text-xs">
            {{ Number(calculateOpenSum(row)) !== 0 ? displayCurrency(calculateOpenSum(row)) : '-' }}
          </td>
          <td class="p-4 truncate max-w-[180px] font-medium">
            {{ row.amount < 0 ? row.credName : row.debName }}
          </td>
          <td class="p-4 text-gray-500 truncate max-w-[350px] text-xs">
            {{ row.text }}
          </td>
        </tr>
      </template>
      <tr v-if="filteredRows.length === 0">
        <td colspan="6" class="p-32 text-center text-gray-400">
          <div class="flex flex-col items-center">
            <UIcon name="i-heroicons-magnifying-glass-circle" class="w-12 h-12 mb-3 opacity-20"/>
            <p class="font-medium">Keine Buchungen gefunden</p>
          </div>
        </td>
      </tr>
      </tbody>
    </table>
  </div>
  <PageLeaveGuard :when="isSyncing"/>

  <UModal v-model:open="cashbookBookingModalOpen" :ui="{ width: 'sm:max-w-lg' }">
    <template #content>
      <UCard>
        <template #header>
          <div class="flex flex-wrap items-center justify-between gap-3">
            <div>
              <div class="text-lg font-semibold">Kassenbucheintrag hinzufügen</div>
              <div class="text-sm text-gray-500">{{ selectedCashbookAccount?.name || "Kassenbuch" }}</div>
            </div>
            <div class="flex flex-wrap items-center gap-2">
              <UBadge color="neutral" variant="subtle">
                Konto {{ selectedCashbookAccount?.datevNumber || selectedCashbookAccount?.iban }}
              </UBadge>
              <UBadge :color="currentCashbookBalance < 0 ? 'error' : 'success'" variant="subtle">
                Bestand {{ displayCurrency(currentCashbookBalance) }}
              </UBadge>
            </div>
          </div>
        </template>

        <div class="space-y-4">
          <div class="space-y-3">
            <UFormField label="Buchungsdatum">
              <UInput v-model="cashbookForm.date" type="date" />
            </UFormField>
            <UFormField label="Betrag">
              <UInput v-model="cashbookForm.amount" type="number" min="0" step="0.01" placeholder="0,00" />
            </UFormField>
            <div class="grid gap-3 sm:grid-cols-2">
              <button
                  type="button"
                  class="w-full rounded-lg border px-4 py-3 text-left transition"
                  :class="cashbookForm.direction === 'income'
                    ? 'border-emerald-500 bg-emerald-50 dark:bg-emerald-950/30'
                    : 'border-gray-200 bg-white hover:border-gray-300 dark:border-gray-800 dark:bg-gray-900'"
                  @click="cashbookForm.direction = 'income'"
              >
                <div class="font-semibold text-emerald-700 dark:text-emerald-300">Einnahme</div>
                <div class="text-sm text-gray-500">Bargeld kommt in die Kasse.</div>
              </button>
              <button
                  type="button"
                  class="w-full rounded-lg border px-4 py-3 text-left transition"
                  :class="cashbookForm.direction === 'expense'
                    ? 'border-red-500 bg-red-50 dark:bg-red-950/30'
                    : 'border-gray-200 bg-white hover:border-gray-300 dark:border-gray-800 dark:bg-gray-900'"
                  @click="cashbookForm.direction = 'expense'"
              >
                <div class="font-semibold text-red-700 dark:text-red-300">Ausgabe</div>
                <div class="text-sm text-gray-500">Bargeld wird aus der Kasse entnommen.</div>
              </button>
            </div>
          </div>
        </div>

        <template #footer>
          <div class="flex justify-end gap-2">
            <UButton color="neutral" variant="ghost" @click="cashbookBookingModalOpen = false">
              Abbrechen
            </UButton>
            <UButton color="primary" icon="i-heroicons-check" :loading="savingCashbookBooking" @click="saveCashbookBooking">
              Anlegen und bearbeiten
            </UButton>
          </div>
        </template>
      </UCard>
    </template>
  </UModal>

  <UModal v-model:open="suggestionsModalOpen" :ui="{ width: 'sm:max-w-6xl' }">
    <template #content>
      <UCard>
        <template #header>
          <div class="flex items-center justify-between gap-3">
            <div>
              <div class="text-lg font-semibold">Vorschläge für Bankbuchungen</div>
              <div class="text-sm text-gray-500">Direkte Zuweisung von passenden Rechnungen und Eingangsbelegen</div>
            </div>
            <UBadge color="primary" variant="subtle">{{ suggestionCount }}</UBadge>
          </div>
        </template>

      <div v-if="rowsWithSuggestions.length > 0" class="grid grid-cols-1 lg:grid-cols-3 gap-4 min-h-[520px]">
        <div class="lg:col-span-1 border rounded-lg overflow-hidden dark:border-gray-800">
          <div
              v-for="entry in rowsWithSuggestions"
              :key="entry.row.id"
              class="p-3 border-b dark:border-gray-800 cursor-pointer transition-colors"
              :class="selectedSuggestionRowId === entry.row.id || (!selectedSuggestionRowId && selectedSuggestionRow?.row.id === entry.row.id) ? 'bg-primary-50 dark:bg-primary-900/20' : 'hover:bg-gray-50 dark:hover:bg-gray-900/50'"
              @click="selectedSuggestionRowId = entry.row.id"
          >
            <div class="flex items-start justify-between gap-2">
              <div class="min-w-0">
                <div class="text-sm font-medium truncate">{{ entry.row.amount < 0 ? entry.row.credName : entry.row.debName }}</div>
                <div class="text-xs text-gray-500 truncate">{{ entry.row.text || 'Ohne Verwendungszweck' }}</div>
              </div>
              <div class="text-xs font-mono whitespace-nowrap" :class="entry.row.amount >= 0 ? 'text-green-600' : 'text-rose-600'">
                {{ displayCurrency(entry.row.amount) }}
              </div>
            </div>
            <div class="mt-2 flex flex-wrap gap-1">
              <UBadge v-if="entry.suggestions?.topDocument" size="xs" color="emerald" variant="subtle">Rechnung</UBadge>
              <UBadge v-if="entry.suggestions?.topIncomingInvoice" size="xs" color="error" variant="subtle">Eingangsbeleg</UBadge>
            </div>
          </div>
        </div>

        <div class="lg:col-span-2 space-y-3" v-if="selectedSuggestionRow">
          <div class="rounded-lg border dark:border-gray-800 p-4 bg-gray-50 dark:bg-gray-900/50">
            <div class="flex items-start justify-between gap-3">
              <div>
                <div class="text-sm font-semibold">{{ selectedSuggestionRow.row.amount < 0 ? selectedSuggestionRow.row.credName : selectedSuggestionRow.row.debName }}</div>
                <div class="text-xs text-gray-500 mt-1">{{ selectedSuggestionRow.row.text || 'Ohne Verwendungszweck' }}</div>
                <div class="text-xs text-gray-400 mt-1">{{ $dayjs(getStatementDate(selectedSuggestionRow.row)).format("DD.MM.YYYY") }}</div>
              </div>
              <div class="text-right">
                <div class="font-mono font-semibold" :class="selectedSuggestionRow.row.amount >= 0 ? 'text-green-600' : 'text-rose-600'">{{ displayCurrency(selectedSuggestionRow.row.amount) }}</div>
                <div class="text-xs text-gray-400">Offen {{ displayCurrency(calculateOpenSum(selectedSuggestionRow.row)) }}</div>
              </div>
            </div>
          </div>

          <div v-if="selectedSuggestionRow.suggestions?.topDocument" class="rounded-lg border border-emerald-200 bg-emerald-50/70 px-4 py-3">
            <div class="flex items-start justify-between gap-3">
              <div class="min-w-0">
                <div class="text-sm font-semibold text-emerald-700">Rechnung {{ selectedSuggestionRow.suggestions.topDocument.documentNumber }}</div>
                <div class="text-xs text-gray-600 mt-1">{{ selectedSuggestionRow.suggestions.topDocument.customer?.name }} | Offen {{ displayCurrency(selectedSuggestionRow.suggestions.topDocument.openSum) }}</div>
                <div class="mt-2 flex flex-wrap gap-1" v-if="selectedSuggestionRow.suggestions.topDocument.suggestionAmountLabel || selectedSuggestionRow.suggestions.topDocument.suggestionPurposeMatches?.length">
                  <UBadge v-if="selectedSuggestionRow.suggestions.topDocument.suggestionAmountLabel" size="xs" color="emerald" variant="subtle">
                    {{ selectedSuggestionRow.suggestions.topDocument.suggestionAmountLabel }}
                  </UBadge>
                  <UBadge v-for="match in selectedSuggestionRow.suggestions.topDocument.suggestionPurposeMatches" :key="`modal-doc-${selectedSuggestionRow.row.id}-${match}`" size="xs" color="amber" variant="subtle">
                    VWZ: {{ match }}
                  </UBadge>
                </div>
              </div>
              <UButton size="sm" color="emerald" @click="handleAssignDocument(selectedSuggestionRow.row, selectedSuggestionRow.suggestions.topDocument, $event)">
                Zuweisen
              </UButton>
              <UButton size="sm" color="gray" variant="ghost" @click="dismissSuggestion(selectedSuggestionRow.row, selectedSuggestionRow.suggestions.topDocument.suggestionKey, $event)">
                Ablehnen
              </UButton>
            </div>
          </div>

          <div v-if="selectedSuggestionRow.suggestions?.topIncomingInvoice" class="rounded-lg border border-rose-200 bg-rose-50/70 px-4 py-3">
            <div class="flex items-start justify-between gap-3">
              <div class="min-w-0">
                <div class="text-sm font-semibold text-rose-700">Eingangsbeleg {{ selectedSuggestionRow.suggestions.topIncomingInvoice.reference || '-' }}</div>
                <div class="text-xs text-gray-600 mt-1">{{ selectedSuggestionRow.suggestions.topIncomingInvoice.vendor?.name }} | Offen {{ displayCurrency(getInvoiceSum(selectedSuggestionRow.suggestions.topIncomingInvoice, true)) }}</div>
                <div class="mt-2 flex flex-wrap gap-1" v-if="selectedSuggestionRow.suggestions.topIncomingInvoice.suggestionAmountLabel || selectedSuggestionRow.suggestions.topIncomingInvoice.suggestionPurposeMatches?.length">
                  <UBadge v-if="selectedSuggestionRow.suggestions.topIncomingInvoice.suggestionAmountLabel" size="xs" color="emerald" variant="subtle">
                    {{ selectedSuggestionRow.suggestions.topIncomingInvoice.suggestionAmountLabel }}
                  </UBadge>
                  <UBadge v-for="match in selectedSuggestionRow.suggestions.topIncomingInvoice.suggestionPurposeMatches" :key="`modal-invoice-${selectedSuggestionRow.row.id}-${match}`" size="xs" color="amber" variant="subtle">
                    VWZ: {{ match }}
                  </UBadge>
                </div>
              </div>
              <UButton size="sm" color="error" @click="handleAssignIncomingInvoice(selectedSuggestionRow.row, selectedSuggestionRow.suggestions.topIncomingInvoice, $event)">
                Zuweisen
              </UButton>
              <UButton size="sm" color="gray" variant="ghost" @click="dismissSuggestion(selectedSuggestionRow.row, selectedSuggestionRow.suggestions.topIncomingInvoice.suggestionKey, $event)">
                Ablehnen
              </UButton>
            </div>
          </div>
        </div>
      </div>

        <div v-else class="py-10 text-center text-gray-400">
          <UIcon name="i-heroicons-sparkles" class="w-10 h-10 mx-auto mb-2 opacity-30"/>
          <p>Keine Vorschläge für die aktuelle Filterung vorhanden.</p>
        </div>
      </UCard>
    </template>
  </UModal>
</template>
