<script setup>
import dayjs from "dayjs"

const router = useRouter()

const props = defineProps({
  queryStringData: {
    type: String
  },
  item: {
    type: Object,
    required: true
  },
  topLevelType: {
    type: String,
    required: true
  },
  platform: {
    type: String,
    required: true
  }
})

const loading = ref(true)
const incomingInvoices = ref([])
const statementAllocations = ref([])
const selectedYear = ref(String(dayjs().year()))
const selectedMonth = ref("all")

const currency = (value) => `${Number(value || 0).toFixed(2).replace(".", ",")} EUR`
const currentAccountId = computed(() => String(props.item?.id ?? ""))
const sameAccount = (value) => String(value ?? "") === currentAccountId.value
const getStatementId = (allocation) => allocation?.bankstatement?.id || allocation?.bs_id?.id || allocation?.bs_id || null
const getStatementLike = (allocation) => allocation?.bankstatement || (typeof allocation?.bs_id === "object" ? allocation.bs_id : null)
const getAllocationDate = (allocation) => {
  const statement = getStatementLike(allocation)

  return statement?.date || statement?.valueDate || allocation?.bs_id?.date || allocation?.bs_id?.valueDate || allocation?.manualBookingDate || null
}
const getAllocationPartner = (allocation) => {
  const statement = getStatementLike(allocation)

  if (!statement && allocation?.manualBookingDate) return "Manuelle Buchung"

  return statement?.debName || statement?.credName || statement?.partner || allocation?.bs_id?.debName || allocation?.bs_id?.credName || ""
}
const getAllocationDescription = (allocation) => {
  const statement = getStatementLike(allocation)

  return allocation?.description || statement?.purpose || statement?.text || statement?.description || allocation?.bs_id?.purpose || allocation?.bs_id?.text || ""
}
const hasContent = (value) => value !== null && value !== undefined && String(value).trim() !== ""
const isContraAllocation = (allocation) =>
    sameAccount(allocation.contraAccount?.id || allocation.contraAccount)
    || sameAccount(allocation.contraOwnaccount?.id || allocation.contraOwnaccount)

const touchesCurrentAccount = (allocation) =>
    sameAccount(allocation.account?.id || allocation.account)
    || sameAccount(allocation.ownaccount?.id || allocation.ownaccount)
    || isContraAllocation(allocation)

const monthItems = [
  { label: "Ganzes Jahr", value: "all" },
  { label: "Januar", value: "1" },
  { label: "Februar", value: "2" },
  { label: "März", value: "3" },
  { label: "April", value: "4" },
  { label: "Mai", value: "5" },
  { label: "Juni", value: "6" },
  { label: "Juli", value: "7" },
  { label: "August", value: "8" },
  { label: "September", value: "9" },
  { label: "Oktober", value: "10" },
  { label: "November", value: "11" },
  { label: "Dezember", value: "12" }
]

const allAllocations = computed(() => {
  const statementRows = statementAllocations.value.map((allocation) => ({
    ...allocation,
    type: "statementallocation",
    bankstatement: allocation.bankstatement || getStatementLike(allocation),
    date: getAllocationDate(allocation),
    partner: getAllocationPartner(allocation),
    description: getAllocationDescription(allocation),
    amount: Number(allocation.amount || 0) * (isContraAllocation(allocation) ? -1 : 1)
  }))

  const incomingInvoiceRows = incomingInvoices.value.flatMap((invoice) => {
    return (invoice.accounts || [])
      .filter((account) => sameAccount(account.account?.id || account.account))
      .map((account, index) => ({
        id: `${invoice.id}-${index}`,
        incominginvoiceid: invoice.id,
        type: "incominginvoice",
        amount: Number(account.amountGross || account.amountNet || 0),
        date: invoice.date,
        partner: invoice.vendor?.name || "",
        description: account.description || invoice.description || "",
        color: invoice.expense ? "red" : "green",
        expense: invoice.expense,
        reference: invoice.reference || "-"
      }))
  })

  return [...statementRows, ...incomingInvoiceRows]
})

const yearItems = computed(() => {
  const years = [...new Set(
    allAllocations.value
      .map((allocation) => allocation.bankstatement?.date || allocation.date)
      .filter(Boolean)
      .map((date) => String(dayjs(date).year()))
  )].sort((a, b) => Number(b) - Number(a))

  return years.length > 0
    ? years.map((year) => ({ label: year, value: year }))
    : [{ label: String(dayjs().year()), value: String(dayjs().year()) }]
})

const renderedAllocations = computed(() => {
  return allAllocations.value.filter((allocation) => {
    const allocationDateValue = allocation.bankstatement?.date || allocation.date
    const allocationDate = allocationDateValue ? dayjs(allocationDateValue) : null

    if (allocationDate && allocationDate.year().toString() !== selectedYear.value) {
      return false
    }

    if (allocationDate && selectedMonth.value !== "all" && allocationDate.month() + 1 !== Number(selectedMonth.value)) {
      return false
    }

    return true
  })
})

const totals = computed(() => {
  return renderedAllocations.value.reduce((acc, allocation) => {
    const amount = Number(allocation.amount || 0)

    if (allocation.incominginvoiceid) {
      if (allocation.expense) {
        acc.expenses += amount
        acc.balance -= amount
      } else {
        acc.income += amount
        acc.balance += amount
      }
    } else {
      if (amount < 0) {
        acc.expenses += Math.abs(amount)
      } else {
        acc.income += amount
      }
      acc.balance += amount
    }

    return acc
  }, { income: 0, expenses: 0, balance: 0 })
})

const columns = [
  { accessorKey: "amount", header: "Betrag" },
  { accessorKey: "date", header: "Datum" },
  { accessorKey: "partner", header: "Partner" },
  { accessorKey: "description", header: "Beschreibung" }
]

const setup = async () => {
  loading.value = true

  statementAllocations.value = (await useEntities("statementallocations").select("*, bankstatement(*), createddocument(*), incominginvoice(*)"))
    .filter((allocation) => touchesCurrentAccount(allocation))

  incomingInvoices.value = (await useEntities("incominginvoices").select("*, vendor(*)"))
    .filter((invoice) => (invoice.accounts || []).some((account) => sameAccount(account.account?.id || account.account)))

  const firstYear = yearItems.value[0]?.value
  if (firstYear && !yearItems.value.some((item) => item.value === selectedYear.value)) {
    selectedYear.value = firstYear
  }

  loading.value = false
}

setup()

const unwrapAllocationRow = (allocationLike) => allocationLike?.original || allocationLike

const selectAllocation = (allocationLike) => {
  const allocation = unwrapAllocationRow(allocationLike)

  if (!allocation) {
    return
  }

  const statementId = getStatementId(allocation)

  if (allocation.type === "statementallocation" && statementId) {
    router.push(`/banking/statements/edit/${statementId}`)
  } else if (allocation.type === "incominginvoice" && allocation.incominginvoiceid) {
    router.push(`/incomingInvoices/show/${allocation.incominginvoiceid}`)
  }
}
</script>

<template>
  <UCard class="mt-5">
    <div class="space-y-4">
      <div class="flex flex-col gap-3 md:flex-row md:items-end">
        <UFormField label="Jahr" class="w-full md:w-48">
          <USelectMenu
              v-model="selectedYear"
              :items="yearItems"
              value-key="value"
              label-key="label"
              class="w-full"
          />
        </UFormField>

        <UFormField label="Monat" class="w-full md:w-56">
          <USelectMenu
              v-model="selectedMonth"
              :items="monthItems"
              value-key="value"
              label-key="label"
              class="w-full"
          />
        </UFormField>
      </div>

      <div class="grid gap-3 md:grid-cols-3">
        <UCard>
          <div class="text-sm text-gray-500 dark:text-gray-400">Einnahmen</div>
          <div class="mt-1 text-xl font-semibold">{{ currency(totals.income) }}</div>
        </UCard>

        <UCard>
          <div class="text-sm text-gray-500 dark:text-gray-400">Ausgaben</div>
          <div class="mt-1 text-xl font-semibold">{{ currency(totals.expenses) }}</div>
        </UCard>

        <UCard>
          <div class="text-sm text-gray-500 dark:text-gray-400">Saldo</div>
          <div class="mt-1 text-xl font-semibold">{{ currency(totals.balance) }}</div>
        </UCard>
      </div>

      <div v-if="!loading" class="overflow-auto max-h-[60vh]">
        <UTable
            :data="renderedAllocations"
            :columns="normalizeTableColumns(columns)"
            :on-select="selectAllocation"
            class="w-full"
        >
          <template #amount-cell="{ row }">
            <span class="text-right text-error" v-if="row.original.amount < 0 || row.original.color === 'red'">{{ useCurrency(row.original.amount) }}</span>
            <span class="text-right text-primary-500" v-else-if="row.original.amount > 0 || row.original.color === 'green'">{{ useCurrency(row.original.amount) }}</span>
            <span v-else>{{ useCurrency(row.original.amount) }}</span>
          </template>

          <template #date-cell="{ row }">
            {{ row.original.date && dayjs(row.original.date).isValid() ? dayjs(row.original.date).format('DD.MM.YYYY') : '-' }}
          </template>

          <template #partner-cell="{ row }">
            <div class="truncate">{{ hasContent(row.original.partner) ? row.original.partner : '-' }}</div>
          </template>

          <template #description-cell="{ row }">
            <UTooltip :text="hasContent(row.original.description) ? row.original.description : '-'">
              <div class="max-w-[22rem] truncate">{{ hasContent(row.original.description) ? row.original.description : '-' }}</div>
            </UTooltip>
          </template>
          <template #empty>
            <TableEmptyState label="Keine Buchungen im ausgewählten Zeitraum" />
          </template>
        </UTable>
      </div>

      <UProgress v-else animation="carousel" class="w-3/4 mx-auto" />
    </div>
  </UCard>
</template>
