<script setup lang="ts">
import dayjs from "dayjs"
import {
  DEPRECIATION_METHOD_ITEMS,
  ensureDepreciationDefaults,
  getAssetDepreciationStatus,
  getIncomingInvoiceDepreciationRows,
  getStatementAllocationDepreciationRow,
  isDepreciationBookingMode,
  normalizeIncomingInvoiceAccount
} from "~/composables/useDepreciation"

const toast = useToast()

const loading = ref(true)
const saving = ref(false)
const incomingInvoices = ref<any[]>([])
const statementAllocations = ref<any[]>([])
const periodStart = ref(dayjs().startOf("month").format("YYYY-MM-DD"))
const periodEnd = ref(dayjs().endOf("month").format("YYYY-MM-DD"))
const selectedAsset = ref<any | null>(null)
const editState = ref<any | null>(null)
const editOpen = computed({
  get: () => !!selectedAsset.value,
  set: (value: boolean) => {
    if (!value) closeEdit()
  }
})

const formatCurrency = (value: number) => new Intl.NumberFormat("de-DE", {
  style: "currency",
  currency: "EUR"
}).format(Number(value || 0))

const isRelevantInputInvoice = (invoice: any) => invoice?.state === "Gebucht" && !!invoice?.date
const normalizedPeriod = computed(() => {
  const start = dayjs(periodStart.value)
  const end = dayjs(periodEnd.value)

  if (start.isValid() && end.isValid() && start.isAfter(end, "day")) {
    return {
      start: end.startOf("day"),
      end: start.endOf("day"),
    }
  }

  return {
    start: start.isValid() ? start.startOf("day") : dayjs().startOf("month"),
    end: end.isValid() ? end.endOf("day") : dayjs().endOf("month"),
  }
})

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

  try {
    const [invoices, allocations] = await Promise.all([
      useEntities("incominginvoices").select("*, vendor(*)"),
      useEntities("statementallocations").select("*, bankstatement(*), vendor(*), customer(*)")
    ])

    incomingInvoices.value = (invoices || []).filter(isRelevantInputInvoice)
    statementAllocations.value = (allocations || []).filter((item: any) => Number(item?.amount || 0) < 0)
  } finally {
    loading.value = false
  }
}

const depreciationAssets = computed(() => {
  const invoiceAssets = incomingInvoices.value.flatMap((invoice: any) => {
    return (invoice.accounts || [])
      .map((account: any, index: number) => {
        const normalized = ensureDepreciationDefaults(normalizeIncomingInvoiceAccount(account, invoice.date), invoice.date)
        if (!isDepreciationBookingMode(normalized.bookingMode)) return null

        const status = getAssetDepreciationStatus({
          amountNet: Number(normalized.amountNet || 0),
          depreciationMonths: normalized.depreciationMonths,
          depreciationStartDate: normalized.depreciationStartDate || invoice.date,
          depreciationMethod: normalized.depreciationMethod,
          residualValue: normalized.residualValue,
        }, normalizedPeriod.value.end)

        const currentPeriodRow = getIncomingInvoiceDepreciationRows(invoice, normalizedPeriod.value.start, normalizedPeriod.value.end)
          .find((row: any) => row.index === index)

        return {
          key: `invoice-${invoice.id}-${index}`,
          sourceType: "incominginvoice",
          sourceId: invoice.id,
          accountIndex: index,
          label: normalized.depreciationLabel || normalized.description || invoice.reference || `Eingangsbeleg ${invoice.id}`,
          group: normalized.depreciationGroup || null,
          mode: normalized.bookingMode,
          method: normalized.depreciationMethod,
          months: Number(normalized.depreciationMonths || 0),
          startDate: normalized.depreciationStartDate || invoice.date,
          residualValue: Number(normalized.residualValue || 0),
          originalValue: Number(normalized.amountNet || 0),
          currentPeriodAmount: Number(currentPeriodRow?.amount || 0),
          depreciated: status.depreciated,
          remaining: status.remaining,
          progressPercent: status.progressPercent,
          vendorName: invoice.vendor?.name || "-",
          reference: invoice.reference || "-",
          sourceRecord: invoice,
        }
      })
      .filter(Boolean)
  })

  const allocationAssets = statementAllocations.value
    .map((allocation: any) => {
      if (!isDepreciationBookingMode(allocation?.bookingMode)) return null

      const status = getAssetDepreciationStatus({
        amount: Math.abs(Number(allocation.amount || 0)),
        depreciationMonths: allocation.depreciationMonths,
        depreciationStartDate: allocation.depreciationStartDate || allocation.created_at,
        depreciationMethod: allocation.depreciationMethod,
        residualValue: allocation.residualValue,
      }, normalizedPeriod.value.end)

      const currentPeriodRow = getStatementAllocationDepreciationRow(allocation, normalizedPeriod.value.start, normalizedPeriod.value.end)

      return {
        key: `allocation-${allocation.id}`,
        sourceType: "statementallocation",
        sourceId: allocation.id,
        accountIndex: null,
        label: allocation.depreciationLabel || allocation.description || "Direkte Abschreibung",
        group: allocation.depreciationGroup || null,
        mode: allocation.bookingMode,
        method: allocation.depreciationMethod || "linear",
        months: Number(allocation.depreciationMonths || 0),
        startDate: allocation.depreciationStartDate || allocation.created_at,
        residualValue: Number(allocation.residualValue || 0),
        originalValue: Math.abs(Number(allocation.amount || 0)),
        currentPeriodAmount: Number(currentPeriodRow?.amount || 0),
        depreciated: status.depreciated,
        remaining: status.remaining,
        progressPercent: status.progressPercent,
        vendorName: allocation.vendor?.name || allocation.customer?.name || "-",
        reference: allocation.description || "-",
        sourceRecord: allocation,
      }
    })
    .filter(Boolean)

  return [...invoiceAssets, ...allocationAssets]
    .sort((left: any, right: any) => Number(right.originalValue) - Number(left.originalValue))
})

const groupedAssets = computed(() => {
  const groups = new Map<string, any>()

  depreciationAssets.value.forEach((asset: any) => {
    const groupKey = asset.group || asset.key
    const current = groups.get(groupKey) || {
      key: groupKey,
      label: asset.group || asset.label,
      isBundle: !!asset.group,
      assets: [],
      originalValue: 0,
      depreciated: 0,
      remaining: 0,
      currentPeriodAmount: 0,
    }

    current.assets.push(asset)
    current.originalValue += asset.originalValue
    current.depreciated += asset.depreciated
    current.remaining += asset.remaining
    current.currentPeriodAmount += asset.currentPeriodAmount
    groups.set(groupKey, current)
  })

  return Array.from(groups.values()).map((group: any) => ({
    ...group,
    originalValue: Number(group.originalValue.toFixed(2)),
    depreciated: Number(group.depreciated.toFixed(2)),
    remaining: Number(group.remaining.toFixed(2)),
    currentPeriodAmount: Number(group.currentPeriodAmount.toFixed(2)),
    residualValue: Number(group.assets.reduce((sum: number, asset: any) => sum + Number(asset.residualValue || 0), 0).toFixed(2)),
    progressPercent: getProgressPercent(
      group.depreciated,
      group.originalValue,
      group.assets.reduce((sum: number, asset: any) => sum + Number(asset.residualValue || 0), 0)
    ),
  }))
})

const totals = computed(() => {
  return groupedAssets.value.reduce((sum: any, group: any) => ({
    originalValue: Number((sum.originalValue + group.originalValue).toFixed(2)),
    depreciated: Number((sum.depreciated + group.depreciated).toFixed(2)),
    remaining: Number((sum.remaining + group.remaining).toFixed(2)),
    currentPeriodAmount: Number((sum.currentPeriodAmount + group.currentPeriodAmount).toFixed(2)),
    count: sum.count + group.assets.length,
    bundleCount: sum.bundleCount + (group.isBundle ? 1 : 0),
  }), { originalValue: 0, depreciated: 0, remaining: 0, currentPeriodAmount: 0, count: 0, bundleCount: 0 })
})

const getProgressPercent = (depreciated: number, originalValue: number, residualValue: number) => {
  const depreciableBase = Math.max(0, Number(originalValue || 0) - Number(residualValue || 0))
  if (!depreciableBase) return 0
  return Math.min(100, Number(((Number(depreciated || 0) / depreciableBase) * 100).toFixed(2)))
}

const startEdit = (asset: any) => {
  selectedAsset.value = asset
  editState.value = {
    depreciationLabel: asset.label,
    depreciationGroup: asset.group || "",
    depreciationMethod: asset.method || "linear",
    depreciationMonths: asset.months || 36,
    depreciationStartDate: dayjs(asset.startDate).format("YYYY-MM-DD"),
    residualValue: asset.residualValue || 0,
  }
}

const closeEdit = () => {
  selectedAsset.value = null
  editState.value = null
}

const saveAsset = async () => {
  if (!selectedAsset.value || !editState.value) return
  saving.value = true

  try {
    if (selectedAsset.value.sourceType === "incominginvoice") {
      const source = selectedAsset.value.sourceRecord
      const nextAccounts = [...(source.accounts || [])]
      nextAccounts[selectedAsset.value.accountIndex] = {
        ...nextAccounts[selectedAsset.value.accountIndex],
        depreciationLabel: editState.value.depreciationLabel,
        depreciationGroup: selectedAsset.value.mode === "depreciation_bundle" ? editState.value.depreciationGroup : "",
        depreciationMethod: editState.value.depreciationMethod,
        depreciationMonths: Number(editState.value.depreciationMonths || 0),
        depreciationStartDate: editState.value.depreciationStartDate,
        residualValue: Number(editState.value.residualValue || 0),
      }

      const payload = {
        ...source,
        vendor: source.vendor?.id || source.vendor,
        accounts: nextAccounts,
      }
      delete payload.statementallocations
      delete payload.files
      await useEntities("incominginvoices").update(source.id, payload, true)
    } else {
      const source = selectedAsset.value.sourceRecord
      await useEntities("statementallocations").update(source.id, {
        depreciationLabel: editState.value.depreciationLabel,
        depreciationGroup: selectedAsset.value.mode === "depreciation_bundle" ? editState.value.depreciationGroup : null,
        depreciationMethod: editState.value.depreciationMethod,
        depreciationMonths: Number(editState.value.depreciationMonths || 0),
        depreciationStartDate: editState.value.depreciationStartDate,
        residualValue: Number(editState.value.residualValue || 0),
      }, true)
    }

    toast.add({ title: "Abschreibung gespeichert", color: "success" })
    closeEdit()
    await loadData()
  } finally {
    saving.value = false
  }
}

onMounted(loadData)
</script>

<template>
  <UDashboardNavbar title="Abschreibungen">
    <template #right>
      <div class="flex items-center gap-2">
        <UInput v-model="periodStart" type="date" class="w-44" />
        <UInput v-model="periodEnd" type="date" class="w-44" />
        <UButton icon="i-heroicons-arrow-path" variant="outline" :loading="loading" @click="loadData">
          Aktualisieren
        </UButton>
      </div>
    </template>
  </UDashboardNavbar>

  <UDashboardPanelContent class="space-y-6 p-4 md:p-6">
    <div class="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
      <UCard>
        <div class="text-sm text-gray-500 dark:text-gray-400">Anschaffungswert</div>
        <div class="mt-2 text-2xl font-semibold">{{ formatCurrency(totals.originalValue) }}</div>
        <div class="mt-2 text-sm text-gray-500 dark:text-gray-400">{{ totals.count }} Abschreibungspositionen</div>
      </UCard>
      <UCard>
        <div class="text-sm text-gray-500 dark:text-gray-400">Bereits abgeschrieben</div>
        <div class="mt-2 text-2xl font-semibold text-primary-600 dark:text-primary-400">{{ formatCurrency(totals.depreciated) }}</div>
        <div class="mt-2 text-sm text-gray-500 dark:text-gray-400">Stand {{ normalizedPeriod.end.format("DD.MM.YYYY") }}</div>
      </UCard>
      <UCard>
        <div class="text-sm text-gray-500 dark:text-gray-400">Restbuchwert</div>
        <div class="mt-2 text-2xl font-semibold text-amber-600 dark:text-amber-400">{{ formatCurrency(totals.remaining) }}</div>
        <div class="mt-2 text-sm text-gray-500 dark:text-gray-400">Nach Restwertlogik</div>
      </UCard>
      <UCard>
        <div class="text-sm text-gray-500 dark:text-gray-400">Abschreibung im Zeitraum</div>
        <div class="mt-2 text-2xl font-semibold text-error">{{ formatCurrency(totals.currentPeriodAmount) }}</div>
        <div class="mt-2 text-sm text-gray-500 dark:text-gray-400">{{ normalizedPeriod.start.format("DD.MM.YYYY") }} - {{ normalizedPeriod.end.format("DD.MM.YYYY") }}</div>
      </UCard>
    </div>

    <div class="space-y-4">
      <UCard v-for="group in groupedAssets" :key="group.key">
        <template #header>
          <div class="flex flex-col gap-3 md:flex-row md:items-start md:justify-between">
            <div>
              <div class="flex items-center gap-2">
                <span class="font-semibold">{{ group.label }}</span>
                <UBadge v-if="group.isBundle" color="warning" variant="soft">Sammelposten</UBadge>
                <UBadge color="neutral" variant="soft">{{ group.assets.length }} Positionen</UBadge>
              </div>
              <div class="mt-1 text-sm text-gray-500 dark:text-gray-400">
                {{ formatCurrency(group.depreciated) }} abgeschrieben | {{ formatCurrency(group.remaining) }} Restbuchwert
              </div>
            </div>
            <div class="min-w-52 space-y-2">
              <div class="flex justify-between text-sm">
                <span>Fortschritt</span>
                <span>{{ group.progressPercent.toFixed(1) }}%</span>
              </div>
              <div class="h-2 overflow-hidden rounded-full bg-gray-200 dark:bg-gray-800">
                <div
                    class="h-full rounded-full bg-primary-500"
                    :style="{ width: `${group.progressPercent}%` }"
                />
              </div>
            </div>
          </div>
        </template>

        <div class="space-y-3">
          <div v-for="asset in group.assets" :key="asset.key" class="rounded-lg border border-gray-200 dark:border-gray-800 p-4">
            <div class="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
              <div class="space-y-1">
                <div class="font-medium text-gray-900 dark:text-white">{{ asset.label }}</div>
                <div class="text-sm text-gray-500 dark:text-gray-400">
                  {{ asset.vendorName }} | {{ asset.reference }}
                </div>
                <div class="flex flex-wrap gap-2 text-xs">
                  <UBadge color="neutral" variant="soft">{{ asset.method === "degressive" ? "Degressiv" : "Linear" }}</UBadge>
                  <UBadge color="neutral" variant="soft">{{ asset.months }} Monate</UBadge>
                  <UBadge color="neutral" variant="soft">Start {{ dayjs(asset.startDate).format("MM/YYYY") }}</UBadge>
                  <UBadge color="neutral" variant="soft">Restwert {{ formatCurrency(asset.residualValue) }}</UBadge>
                </div>
              </div>
              <UButton size="sm" variant="outline" icon="i-heroicons-pencil-square" @click="startEdit(asset)">
                Bearbeiten
              </UButton>
            </div>

            <div class="mt-4 grid gap-3 md:grid-cols-4">
              <div>
                <div class="text-xs text-gray-500 dark:text-gray-400">Anschaffungswert</div>
                <div class="mt-1 font-semibold">{{ formatCurrency(asset.originalValue) }}</div>
              </div>
              <div>
                <div class="text-xs text-gray-500 dark:text-gray-400">Abgeschrieben</div>
                <div class="mt-1 font-semibold text-primary-600 dark:text-primary-400">{{ formatCurrency(asset.depreciated) }}</div>
              </div>
              <div>
                <div class="text-xs text-gray-500 dark:text-gray-400">Im Zeitraum</div>
                <div class="mt-1 font-semibold text-error">{{ formatCurrency(asset.currentPeriodAmount) }}</div>
              </div>
              <div>
                <div class="text-xs text-gray-500 dark:text-gray-400">Restbuchwert</div>
                <div class="mt-1 font-semibold text-amber-600 dark:text-amber-400">{{ formatCurrency(asset.remaining) }}</div>
              </div>
            </div>

            <div class="mt-4 space-y-2">
              <div class="flex justify-between text-sm">
                <span>Wirklicher Abschreibungsfortschritt</span>
                <span>{{ getProgressPercent(asset.depreciated, asset.originalValue, asset.residualValue).toFixed(1) }}%</span>
              </div>
              <div class="h-2 overflow-hidden rounded-full bg-gray-200 dark:bg-gray-800">
                <div
                    class="h-full rounded-full bg-primary-500"
                    :style="{ width: `${getProgressPercent(asset.depreciated, asset.originalValue, asset.residualValue)}%` }"
                />
              </div>
            </div>
          </div>
        </div>
      </UCard>
    </div>

    <USlideover v-model:open="editOpen" title="Abschreibung bearbeiten">
      <template #body>
        <div v-if="selectedAsset && editState" class="space-y-4 p-4">
          <UFormField label="Bezeichnung">
            <UInput v-model="editState.depreciationLabel" />
          </UFormField>
          <UFormField v-if="selectedAsset.mode === 'depreciation_bundle'" label="Sammelposten">
            <UInput v-model="editState.depreciationGroup" />
          </UFormField>
          <UFormField label="Methode">
            <USelectMenu v-model="editState.depreciationMethod" :items="DEPRECIATION_METHOD_ITEMS" value-key="value" label-key="label" />
          </UFormField>
          <UFormField label="Dauer (Monate)">
            <UInput v-model="editState.depreciationMonths" type="number" min="1" step="1" />
          </UFormField>
          <UFormField label="Start Abschreibung">
            <UInput v-model="editState.depreciationStartDate" type="date" />
          </UFormField>
          <UFormField label="Restwert">
            <UInput v-model="editState.residualValue" type="number" min="0" step="0.01" />
          </UFormField>
        </div>
      </template>
      <template #footer>
        <div class="flex justify-end gap-2 p-4">
          <UButton variant="ghost" @click="closeEdit">Abbrechen</UButton>
          <UButton :loading="saving" @click="saveAsset">Speichern</UButton>
        </div>
      </template>
    </USlideover>
  </UDashboardPanelContent>
</template>
