"use client";

import CheckCircleRoundedIcon from "@mui/icons-material/CheckCircleRounded";
import CloseRoundedIcon from "@mui/icons-material/CloseRounded";
import DeleteOutlineRoundedIcon from "@mui/icons-material/DeleteOutlineRounded";
import DoneAllRoundedIcon from "@mui/icons-material/DoneAllRounded";
import EditRoundedIcon from "@mui/icons-material/EditRounded";
import ExpandLessRoundedIcon from "@mui/icons-material/ExpandLessRounded";
import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded";
import EuroRoundedIcon from "@mui/icons-material/EuroRounded";
import PhotoCameraRoundedIcon from "@mui/icons-material/PhotoCameraRounded";
import ReceiptLongRoundedIcon from "@mui/icons-material/ReceiptLongRounded";
import TaskAltRoundedIcon from "@mui/icons-material/TaskAltRounded";
import UploadFileRoundedIcon from "@mui/icons-material/UploadFileRounded";
import {
  Box,
  Button,
  Card,
  CardContent,
  Chip,
  Collapse,
  Divider,
  IconButton,
  Link,
  MenuItem,
  Stack,
  TextField,
  Typography,
  useMediaQuery
} from "@mui/material";
import { alpha, useTheme } from "@mui/material/styles";
import { useEffect, useMemo, useState } from "react";

import { ColorPickerField } from "@/components/dashboard/color-picker-field";
import type { DashboardBudget, DashboardExpense, DashboardViewer, DashboardWorkingGroup } from "@/lib/dashboard-types";
import {
  approvalLabel,
  canDeleteExpense,
  canDocumentExpense,
  canManageBudgets,
  canMarkPaid,
  getAvailableApprovalTypes,
  recurrenceLabel,
  requiresManualApproval
} from "@/lib/domain";

type BudgetColumnProps = {
  group: DashboardWorkingGroup;
  viewer: DashboardViewer;
  busy: boolean;
  approvalThreshold: number;
  requiredApprovalTypes: ("CHAIR_A" | "CHAIR_B" | "FINANCE")[];
  focusBudgetId?: string | null;
  onApprove: (expenseId: string, approvalType: "CHAIR_A" | "CHAIR_B" | "FINANCE") => Promise<void>;
  onMarkPaid: (expenseId: string) => Promise<void>;
  onDocument: (expenseId: string, proofUrl?: string) => Promise<void>;
  onUploadProof: (expenseId: string, file: File, invoiceDate: string) => Promise<string>;
  onSaveWorkingGroup: (groupId: string, name: string) => Promise<void>;
  onDeleteWorkingGroup: (groupId: string, groupName: string) => Promise<void>;
  onSaveBudget: (budgetId: string, name: string, totalBudget: string, colorCode: string) => Promise<void>;
  onDeleteBudget: (budgetId: string) => Promise<void>;
  onDeleteExpense: (expenseId: string) => Promise<void>;
};
type BudgetDraft = {
  name: string;
  totalBudget: string;
  colorCode: string;
};

const currencyFormatter = new Intl.NumberFormat("de-DE", {
  style: "currency",
  currency: "EUR"
});

const dateFormatter = new Intl.DateTimeFormat("de-DE", {
  dateStyle: "medium"
});

const wrappingChipSx = {
  height: "auto",
  "& .MuiChip-label": {
    display: "block",
    whiteSpace: "normal",
    py: 0.5
  }
} as const;

function formatCurrency(value: number) {
  return currencyFormatter.format(value);
}

function createDraft(budget: DashboardBudget): BudgetDraft {
  return {
    name: budget.name,
    totalBudget: budget.totalBudget.toFixed(2),
    colorCode: budget.colorCode
  };
}

function StatusChips({ expense }: { expense: DashboardExpense }) {
  return (
    <Stack direction="row" gap={1} useFlexGap flexWrap="wrap">
      <Chip
        label={expense.approvalStatus === "APPROVED" ? "Freigegeben" : "Geplant"}
        color={expense.approvalStatus === "APPROVED" ? "primary" : "default"}
        variant={expense.approvalStatus === "APPROVED" ? "filled" : "outlined"}
        size="small"
        sx={wrappingChipSx}
      />
      {expense.paidAt ? (
        <Chip label="Bezahlt" color="info" size="small" icon={<CheckCircleRoundedIcon />} sx={wrappingChipSx} />
      ) : null}
      {expense.documentedAt ? (
        <Chip label="Dokumentiert" color="success" size="small" icon={<TaskAltRoundedIcon />} sx={wrappingChipSx} />
      ) : null}
      {expense.recurrence === "MONTHLY" ? (
        <Chip
          label={recurrenceLabel(expense.recurrence)}
          color="secondary"
          variant="outlined"
          size="small"
          sx={wrappingChipSx}
        />
      ) : null}
    </Stack>
  );
}

function getApprovedSpend(expenses: DashboardExpense[]) {
  return expenses.reduce((sum, expense) => sum + (expense.approvalStatus === "APPROVED" ? expense.periodAmount : 0), 0);
}

function getPendingSpend(expenses: DashboardExpense[]) {
  return expenses.reduce((sum, expense) => sum + (expense.approvalStatus === "PENDING" ? expense.periodAmount : 0), 0);
}

function getPaidSpend(expenses: DashboardExpense[]) {
  return expenses.reduce((sum, expense) => sum + (expense.paidAt ? expense.periodAmount : 0), 0);
}

export function BudgetColumn({
  group,
  viewer,
  busy,
  approvalThreshold,
  requiredApprovalTypes,
  focusBudgetId,
  onApprove,
  onMarkPaid,
  onDocument,
  onUploadProof,
  onSaveWorkingGroup,
  onDeleteWorkingGroup,
  onSaveBudget,
  onDeleteBudget,
  onDeleteExpense
}: BudgetColumnProps) {
  const theme = useTheme();
  const isDark = theme.palette.mode === "dark";
  const isCompactLayout = useMediaQuery(theme.breakpoints.down("lg"));
  const [budgetDrafts, setBudgetDrafts] = useState<Record<string, BudgetDraft>>({});
  const [editingBudgetId, setEditingBudgetId] = useState<string | null>(null);
  const [isEditingGroup, setIsEditingGroup] = useState(false);
  const [groupDraftName, setGroupDraftName] = useState(group.name);
  const [selectedBudgetId, setSelectedBudgetId] = useState(group.budgets[0]?.id ?? "");
  const [proofFileDrafts, setProofFileDrafts] = useState<Record<string, { file: File; invoiceDate: string }[]>>({});
  const [expandedRecurringExpenses, setExpandedRecurringExpenses] = useState<Record<string, boolean>>({});

  const budgetCardWidth = 352;
  const desktopBudgetGap = 16;
  const desktopBudgetListWidth =
    group.budgets.length * budgetCardWidth + Math.max(group.budgets.length - 1, 0) * desktopBudgetGap;
  const groupCardWidth = Math.max(desktopBudgetListWidth + 64, 456);
  const canEditBudgets = canManageBudgets(viewer.role);

  useEffect(() => {
    setBudgetDrafts(
      Object.fromEntries(group.budgets.map((budget) => [budget.id, createDraft(budget)]))
    );
  }, [group.budgets]);

  useEffect(() => {
    if (editingBudgetId && !group.budgets.some((budget) => budget.id === editingBudgetId)) {
      setEditingBudgetId(null);
    }
  }, [editingBudgetId, group.budgets]);

  useEffect(() => {
    setGroupDraftName(group.name);
  }, [group.name]);

  useEffect(() => {
    if (!group.budgets.some((budget) => budget.id === selectedBudgetId)) {
      setSelectedBudgetId(group.budgets[0]?.id ?? "");
    }
  }, [group.budgets, selectedBudgetId]);

  useEffect(() => {
    if (focusBudgetId && group.budgets.some((budget) => budget.id === focusBudgetId)) {
      setSelectedBudgetId(focusBudgetId);
    }
  }, [focusBudgetId, group.budgets]);

  const approvedSpend = useMemo(
    () => group.budgets.reduce((sum, budget) => sum + getApprovedSpend(budget.expenses), 0),
    [group.budgets]
  );
  const paidSpend = useMemo(
    () => group.budgets.reduce((sum, budget) => sum + getPaidSpend(budget.expenses), 0),
    [group.budgets]
  );
  const pendingSpend = useMemo(
    () => group.budgets.reduce((sum, budget) => sum + getPendingSpend(budget.expenses), 0),
    [group.budgets]
  );
  const releasedSpend = useMemo(
    () => group.budgets.reduce((sum, budget) => sum + budget.releasedAmount + getPaidSpend(budget.expenses), 0),
    [group.budgets]
  );
  const totalCommitted = approvedSpend + pendingSpend;
  const remainingBudget = group.totalBudget - totalCommitted;

  function getDraft(budget: DashboardBudget) {
    return budgetDrafts[budget.id] ?? createDraft(budget);
  }

  function updateDraft(budget: DashboardBudget, patch: Partial<BudgetDraft>) {
    setBudgetDrafts((current) => ({
      ...current,
      [budget.id]: {
        ...getDraft(budget),
        ...patch
      }
    }));
  }

  function resetDraft(budget: DashboardBudget) {
    setBudgetDrafts((current) => ({
      ...current,
      [budget.id]: createDraft(budget)
    }));
  }

  function addProofFiles(expenseId: string, files: FileList | null) {
    if (!files || files.length === 0) {
      return;
    }

    const nextFiles = Array.from(files).map((file) => ({ file, invoiceDate: "" }));
    setProofFileDrafts((current) => ({
      ...current,
      [expenseId]: [...(current[expenseId] ?? []), ...nextFiles]
    }));
  }

  function updateProofInvoiceDate(expenseId: string, index: number, invoiceDate: string) {
    setProofFileDrafts((current) => ({
      ...current,
      [expenseId]: (current[expenseId] ?? []).map((entry, entryIndex) =>
        entryIndex === index ? { ...entry, invoiceDate } : entry
      )
    }));
  }

  function removeProofDraft(expenseId: string, index: number) {
    setProofFileDrafts((current) => ({
      ...current,
      [expenseId]: (current[expenseId] ?? []).filter((_, entryIndex) => entryIndex !== index)
    }));
  }

  const selectedBudget = group.budgets.find((budget) => budget.id === selectedBudgetId) ?? group.budgets[0] ?? null;
  const visibleBudgets = isCompactLayout && selectedBudget ? [selectedBudget] : group.budgets;
  const mobilePrimarySelectSx = {
    width: "100%",
    "& .MuiOutlinedInput-root": {
      minHeight: 64,
      borderRadius: "28px",
      backgroundColor: alpha(theme.palette.background.paper, isDark ? 0.72 : 0.96),
      "& fieldset": {
        borderColor: alpha(theme.palette.primary.main, isDark ? 0.54 : 0.38)
      },
      "&:hover fieldset": {
        borderColor: alpha(theme.palette.primary.main, 0.72)
      },
      "&.Mui-focused fieldset": {
        borderWidth: 2,
        borderColor: theme.palette.primary.main
      }
    },
    "& .MuiInputLabel-root": {
      color: theme.palette.text.secondary
    },
    "& .MuiInputBase-input": {
      fontSize: "1.08rem",
      fontWeight: 600
    }
  } as const;

  return (
    <Card
      sx={{
        minWidth: { xs: 0, md: groupCardWidth },
        width: { xs: "100%", md: groupCardWidth },
        maxWidth: "none",
        flexShrink: 0,
        backgroundColor: alpha(theme.palette.background.paper, isDark ? 0.94 : 0.98),
        backgroundImage: "none",
        touchAction: "pan-x pan-y"
      }}
    >
      <CardContent sx={{ p: 3 }}>
        <Stack spacing={3}>
          <Stack
            direction={{ xs: "column", sm: "row" }}
            justifyContent="space-between"
            alignItems={{ xs: "flex-start", sm: "flex-start" }}
            gap={1.5}
          >
            <Box sx={{ minWidth: 0 }}>
              <Typography variant="h3" sx={{ fontSize: "1.45rem", overflowWrap: "break-word" }}>
                {group.name}
              </Typography>
              <Typography color="text.secondary">
                Gesamtbudgets: {formatCurrency(group.totalBudget)}
              </Typography>
            </Box>
            <Stack direction="row" gap={1} alignItems="center">
              {totalCommitted > group.totalBudget ? <Chip label={"\u00dcber Budget"} color="error" size="small" /> : null}
              {canEditBudgets ? (
                <IconButton
                  size="small"
                  disabled={busy}
                  onClick={() => {
                    if (isEditingGroup) {
                      setGroupDraftName(group.name);
                      setIsEditingGroup(false);
                      return;
                    }

                    setIsEditingGroup(true);
                  }}
                  sx={{
                    border: `1px solid ${alpha(theme.palette.text.primary, 0.12)}`,
                    bgcolor: alpha(theme.palette.background.default, isDark ? 0.72 : 0.65)
                  }}
                >
                  {isEditingGroup ? <CloseRoundedIcon fontSize="small" /> : <EditRoundedIcon fontSize="small" />}
                </IconButton>
              ) : null}
            </Stack>
          </Stack>

          {isEditingGroup ? (
            <Box
              component="form"
              onSubmit={async (event) => {
                event.preventDefault();
                await onSaveWorkingGroup(group.id, groupDraftName);
                setIsEditingGroup(false);
              }}
              sx={{
                p: 2,
                borderRadius: "18px",
                border: `1px solid ${alpha(theme.palette.text.primary, isDark ? 0.12 : 0.08)}`,
                backgroundColor: alpha(theme.palette.background.paper, isDark ? 0.9 : 0.96),
                backgroundImage: "none"
              }}
            >
              <Stack spacing={1.4}>
                <TextField
                  label="AG-Name"
                  size="small"
                  value={groupDraftName}
                  onChange={(event) => setGroupDraftName(event.target.value)}
                  fullWidth
                />
                <Typography variant="body2" color="text.secondary">
                  AGs lassen sich nur löschen, wenn keine Mitglieder, Budgets oder Ausgaben mehr daran hängen.
                </Typography>
                <Stack direction="row" gap={1} useFlexGap flexWrap="wrap">
                  <Button type="submit" variant="contained" disabled={busy}>
                    Speichern
                  </Button>
                  <Button
                    type="button"
                    variant="outlined"
                    disabled={busy}
                    onClick={() => {
                      setGroupDraftName(group.name);
                      setIsEditingGroup(false);
                    }}
                  >
                    Abbrechen
                  </Button>
                  <Button
                    type="button"
                    color="error"
                    variant="outlined"
                    startIcon={<DeleteOutlineRoundedIcon />}
                    disabled={busy}
                    onClick={async () => {
                      if (!window.confirm(`AG "${group.name}" wirklich löschen?`)) {
                        return;
                      }

                      await onDeleteWorkingGroup(group.id, group.name);
                      setIsEditingGroup(false);
                    }}
                  >
                    AG löschen
                  </Button>
                </Stack>
              </Stack>
            </Box>
          ) : null}

          <Stack direction="row" gap={1} useFlexGap flexWrap="wrap">
            <Chip
              icon={<DoneAllRoundedIcon />}
              label={`Freigegeben: ${formatCurrency(approvedSpend)}`}
              sx={{ ...wrappingChipSx, width: "fit-content" }}
            />
            <Chip
              icon={<CheckCircleRoundedIcon />}
              label={`Bezahlt: ${formatCurrency(paidSpend)}`}
              color="info"
              sx={{ ...wrappingChipSx, width: "fit-content" }}
            />
            <Chip
              icon={<ReceiptLongRoundedIcon />}
              label={`Geplant: ${formatCurrency(pendingSpend)}`}
              variant="outlined"
              sx={{ ...wrappingChipSx, width: "fit-content" }}
            />
            <Chip
              icon={<EuroRoundedIcon />}
              label={`Rest: ${formatCurrency(remainingBudget)}`}
              color={remainingBudget < 0 ? "error" : "default"}
              sx={{ ...wrappingChipSx, width: "fit-content" }}
            />
            <Chip
              label={`An AG übergeben: ${formatCurrency(releasedSpend)}`}
              color={releasedSpend > group.totalBudget ? "error" : "default"}
              variant="outlined"
              sx={{ ...wrappingChipSx, width: "fit-content" }}
            />
          </Stack>

          {group.budgets.length === 0 ? (
            <Box
              sx={{
                p: 2.5,
                borderRadius: "18px",
                backgroundColor: alpha(theme.palette.text.primary, isDark ? 0.08 : 0.04)
              }}
            >
              <Typography color="text.secondary">In dieser AG gibt es noch keine Budgets.</Typography>
            </Box>
          ) : null}

          {isCompactLayout && group.budgets.length > 1 ? (
            <TextField
              select
              label="Budget auswählen"
              value={selectedBudget?.id ?? ""}
              onChange={(event) => setSelectedBudgetId(event.target.value)}
              fullWidth
              sx={mobilePrimarySelectSx}
            >
              {group.budgets.map((budget) => (
                <MenuItem key={budget.id} value={budget.id}>
                  {budget.name}
                </MenuItem>
              ))}
            </TextField>
          ) : null}

	          <Box
	            sx={{
	              display: "flex",
	              gap: 2,
	              overflow: "visible",
	              pb: 0,
	              alignItems: "stretch",
	              width: isCompactLayout ? "100%" : desktopBudgetListWidth,
	              minWidth: isCompactLayout ? 0 : desktopBudgetListWidth
	            }}
          >
            {visibleBudgets.map((budget) => {
              const draft = getDraft(budget);
              const isEditing = editingBudgetId === budget.id;
              const budgetApproved = getApprovedSpend(budget.expenses);
              const budgetPaid = getPaidSpend(budget.expenses);
              const budgetPending = getPendingSpend(budget.expenses);
              const budgetReleasedByPayments = getPaidSpend(budget.expenses);
              const budgetReleasedTotal = budget.releasedAmount + budgetReleasedByPayments;
              const budgetCommitted = budgetApproved + budgetPending;
              const budgetRemaining = budget.totalBudget - budgetCommitted;
              const paidPercent = budget.totalBudget > 0 ? Math.min((budgetPaid / budget.totalBudget) * 100, 100) : 0;
              const cumulativePercent =
                budget.totalBudget > 0 ? Math.min((budgetCommitted / budget.totalBudget) * 100, 100) : 0;
              const releasedPercent =
                budget.totalBudget > 0 ? Math.min((budgetReleasedTotal / budget.totalBudget) * 100, 100) : 0;

              return (
                <Box
                  key={budget.id}
                  sx={{
                    minWidth: isCompactLayout ? 0 : budgetCardWidth,
                    width: isCompactLayout ? "100%" : budgetCardWidth,
                    maxWidth: isCompactLayout ? "100%" : budgetCardWidth,
                    flex: "0 0 auto",
                    scrollSnapAlign: "start"
                  }}
                >
                  <Box
                    sx={{
                      p: 2.25,
                      borderRadius: "18px",
                      border: `1px solid ${alpha(budget.colorCode, 0.22)}`,
                      backgroundColor: alpha(budget.colorCode, isDark ? 0.14 : 0.08),
                      backgroundImage: "none",
                      overflow: "hidden",
                      height: "100%"
                    }}
                  >
                    <Stack spacing={2}>
                      <Stack direction="row" justifyContent="space-between" alignItems="flex-start" gap={1.5}>
                        <Box sx={{ minWidth: 0, flex: 1 }}>
                          <Stack direction="row" gap={1.2} alignItems="center">
                            <Box sx={{ width: 18, height: 18, borderRadius: "50%", bgcolor: budget.colorCode, flexShrink: 0 }} />
                            <Typography variant="h4" sx={{ fontSize: "1.15rem", overflowWrap: "break-word" }}>
                              {budget.name}
                            </Typography>
                          </Stack>
                          <Typography color="text.secondary">Budget: {formatCurrency(budget.totalBudget)}</Typography>
                        </Box>
                        {canEditBudgets ? (
                          <IconButton
                            size="small"
                            disabled={busy}
                            onClick={() => {
                              if (isEditing) {
                                resetDraft(budget);
                                setEditingBudgetId(null);
                                return;
                              }

                              setEditingBudgetId(budget.id);
                            }}
                            sx={{
                              border: `1px solid ${alpha(theme.palette.text.primary, 0.12)}`,
                              bgcolor: alpha(theme.palette.background.default, isDark ? 0.72 : 0.65)
                            }}
                          >
                            {isEditing ? <CloseRoundedIcon fontSize="small" /> : <EditRoundedIcon fontSize="small" />}
                          </IconButton>
                        ) : null}
                      </Stack>

                      <Stack direction={{ xs: "column", sm: "row" }} gap={2} alignItems="stretch">
                        <Box sx={{ width: { xs: "100%", sm: 110 }, display: "grid", placeItems: "center" }}>
                          <Box
                            sx={{
                              position: "relative",
                              width: 96,
                              height: 232,
                              borderRadius: "30px",
                              border: `3px solid ${alpha(budget.colorCode, 0.82)}`,
                              backgroundColor: alpha(budget.colorCode, isDark ? 0.12 : 0.06),
                              overflow: "hidden"
                            }}
                          >
                            <Box
                              sx={{
                                position: "absolute",
                                insetInline: 0,
                                bottom: 0,
                                height: `${cumulativePercent}%`,
                                backgroundColor: alpha(budget.colorCode, 0.3),
                                transition: "height 220ms ease"
                              }}
                            />
                            <Box
                              sx={{
                                position: "absolute",
                                insetInline: 0,
                                bottom: 0,
                                height: `${paidPercent}%`,
                                backgroundColor: budget.colorCode,
                                transition: "height 220ms ease"
                              }}
                            />
                            {budgetReleasedTotal > 0 ? (
                              <Box
                                sx={{
                                  position: "absolute",
                                  left: 8,
                                  right: 8,
                                  bottom: `calc(${releasedPercent}% - 1px)`,
                                  borderTop: `2px dashed ${alpha(isDark ? "#FFFFFF" : budget.colorCode, isDark ? 0.82 : 0.9)}`,
                                  zIndex: 2,
                                  pointerEvents: "none"
                                }}
                              />
                            ) : null}
                          </Box>
                        </Box>

                        <Stack spacing={1.2} sx={{ flex: 1, minWidth: 0 }}>
                          <Chip
                            icon={<DoneAllRoundedIcon />}
                            label={`Freigegeben: ${formatCurrency(budgetApproved)}`}
                            sx={{ ...wrappingChipSx, width: "fit-content", bgcolor: alpha(budget.colorCode, 0.14) }}
                          />
                          <Chip
                            icon={<CheckCircleRoundedIcon />}
                            label={`Bezahlt: ${formatCurrency(budgetPaid)}`}
                            color="info"
                            sx={{ ...wrappingChipSx, width: "fit-content" }}
                          />
                          <Chip
                            icon={<ReceiptLongRoundedIcon />}
                            label={`Geplant: ${formatCurrency(budgetPending)}`}
                            variant="outlined"
                            sx={{ ...wrappingChipSx, width: "fit-content" }}
                          />
                          <Chip
                            icon={<EuroRoundedIcon />}
                            label={`Rest: ${formatCurrency(budgetRemaining)}`}
                            color={budgetRemaining < 0 ? "error" : "default"}
                            sx={{ ...wrappingChipSx, width: "fit-content" }}
                          />
                          <Chip
                            label={`An AG übergeben: ${formatCurrency(budgetReleasedTotal)}`}
                            color={budgetReleasedTotal > budget.totalBudget ? "error" : "default"}
                            variant="outlined"
                            sx={{ ...wrappingChipSx, width: "fit-content" }}
                          />
                          {budget.releasedAmount > 0 ? (
                            <Typography variant="caption" color="text.secondary" sx={{ fontSize: "0.76rem" }}>
                              {`Manuell erg\u00e4nzt: ${formatCurrency(budget.releasedAmount)}`}
                            </Typography>
                          ) : null}
                        </Stack>
                      </Stack>

                      {isEditing ? (
                        <Box
                          component="form"
                          onSubmit={async (event) => {
                            event.preventDefault();
                            await onSaveBudget(budget.id, draft.name, draft.totalBudget, draft.colorCode);
                            setEditingBudgetId(null);
                          }}
                        >
                          <Stack spacing={1.4}>
                            <TextField
                              label="Budget-Name"
                              value={draft.name}
                              size="small"
                              onChange={(event) => updateDraft(budget, { name: event.target.value })}
                              fullWidth
                            />
                            <TextField
                              label="Budgetbetrag"
                              value={draft.totalBudget}
                              size="small"
                              type="number"
                              inputProps={{ min: 0, step: 0.01 }}
                              onChange={(event) => updateDraft(budget, { totalBudget: event.target.value })}
                              fullWidth
                            />
                            <ColorPickerField
                              label="Budgetfarbe"
                              value={draft.colorCode}
                              onChange={(value) => updateDraft(budget, { colorCode: value })}
                            />
                            <Stack direction="row" gap={1} useFlexGap flexWrap="wrap">
                              <Button type="submit" variant="contained" disabled={busy}>
                                Speichern
                              </Button>
                              <Button
                                type="button"
                                variant="outlined"
                                disabled={busy}
                                onClick={() => {
                                  resetDraft(budget);
                                  setEditingBudgetId(null);
                                }}
                              >
                                Abbrechen
                              </Button>
                              <Button
                                type="button"
                                color="error"
                                variant="outlined"
                                startIcon={<DeleteOutlineRoundedIcon />}
                                disabled={busy}
                                onClick={async () => {
                                  if (!window.confirm(`Budget "${budget.name}" wirklich l\u00f6schen?`)) {
                                    return;
                                  }

                                  await onDeleteBudget(budget.id);
                                  setEditingBudgetId(null);
                                }}
                              >
                                {"Budget l\u00f6schen"}
                              </Button>
                            </Stack>
                          </Stack>
                        </Box>
                      ) : null}

                      <Divider />

                      <Stack spacing={1.5}>
                        {budget.expenses.length === 0 ? (
                          <Box
                            sx={{
                              p: 2,
                              borderRadius: "16px",
                              backgroundColor: alpha(budget.colorCode, isDark ? 0.14 : 0.08)
                            }}
                          >
                            <Typography variant="body2" color="text.secondary">
                              Noch keine Ausgaben in diesem Budget.
                            </Typography>
                          </Box>
                        ) : null}

                        {budget.expenses.map((expense) => {
	                          const doneApprovalTypes = expense.approvals.map((approval) => approval.approvalType);
	                          const availableApprovals = requiresManualApproval(expense.amount, approvalThreshold)
	                            ? getAvailableApprovalTypes(viewer.approvalPermissions, doneApprovalTypes, requiredApprovalTypes)
	                            : [];
                          const isRecurringSeries = expense.recurrence === "MONTHLY";
                          const isRecurringExpanded = expandedRecurringExpenses[expense.id] ?? false;
                          const canUploadProof = expense.creator.id === viewer.id || canDocumentExpense(viewer.role);

                          return (
                            <Box
                              key={expense.id}
	                              sx={{
	                                p: 2.25,
	                                borderRadius: "18px",
	                                border: `1px solid ${alpha(budget.colorCode, 0.18)}`,
	                                backgroundColor:
	                                  expense.approvalStatus === "APPROVED"
	                                    ? alpha(budget.colorCode, isDark ? 0.16 : 0.08)
	                                    : alpha(budget.colorCode, isDark ? 0.1 : 0.04),
	                                touchAction: "pan-x pan-y"
	                              }}
                            >
                              <Stack spacing={1.4}>
                                <Stack spacing={1}>
                                  <Box sx={{ minWidth: 0 }}>
                                    <Typography
                                      variant="subtitle1"
                                      sx={{ fontWeight: 700, overflowWrap: "break-word" }}
                                    >
                                      {expense.title}
                                    </Typography>
                                    <Typography color="text.secondary" sx={{ overflowWrap: "break-word" }}>
                                      {isRecurringSeries
                                        ? expense.occurrenceCount > 0
                                          ? `${formatCurrency(expense.periodAmount)} im Zeitraum (${expense.occurrenceCount} x ${formatCurrency(expense.amount)}) von ${expense.creator.name}`
                                          : `Noch keine Monatsrate in diesem Zeitraum · ${formatCurrency(expense.amount)} pro Monat · von ${expense.creator.name}`
                                        : `${formatCurrency(expense.amount)} von ${expense.creator.name}`}
                                    </Typography>
                                  </Box>
                                  <StatusChips expense={expense} />
                                </Stack>

                                {expense.description ? (
                                  <Typography variant="body2" color="text.secondary" sx={{ overflowWrap: "break-word" }}>
                                    {expense.description}
                                  </Typography>
                                ) : null}

                                {isRecurringSeries ? (
                                  <Stack spacing={1}>
                                    <Typography variant="body2" color="text.secondary">
                                      {`Abo-Start: ${dateFormatter.format(new Date(expense.recurrenceStartAt ?? expense.createdAt))}`}
                                    </Typography>
                                    {expense.occurrenceCount > 0 ? (
                                      <>
                                        <Button
                                          type="button"
                                          size="small"
                                          variant="text"
                                          onClick={() =>
                                            setExpandedRecurringExpenses((current) => ({
                                              ...current,
                                              [expense.id]: !isRecurringExpanded
                                            }))
                                          }
                                          endIcon={isRecurringExpanded ? <ExpandLessRoundedIcon /> : <ExpandMoreRoundedIcon />}
                                          sx={{ alignSelf: "flex-start", px: 0 }}
                                        >
                                          {isRecurringExpanded
                                            ? "Monatsraten ausblenden"
                                            : `Monatsraten anzeigen (${expense.occurrenceCount})`}
                                        </Button>
                                        <Collapse in={isRecurringExpanded} unmountOnExit>
                                          <Stack spacing={0.8}>
                                            {expense.occurrences.map((occurrence) => (
                                              <Box
                                                key={occurrence.id}
                                                sx={{
                                                  p: 1.2,
                                                  borderRadius: "14px",
                                                  backgroundColor: alpha(budget.colorCode, isDark ? 0.12 : 0.06)
                                                }}
                                              >
                                                <Stack
                                                  direction={{ xs: "column", sm: "row" }}
                                                  justifyContent="space-between"
                                                  gap={0.75}
                                                >
                                                  <Typography variant="body2" sx={{ fontWeight: 600 }}>
                                                    {occurrence.label}
                                                  </Typography>
                                                  <Typography variant="body2" color="text.secondary">
                                                    {formatCurrency(occurrence.amount)} · fällig {dateFormatter.format(new Date(occurrence.dueAt))}
                                                  </Typography>
                                                </Stack>
                                              </Box>
                                            ))}
                                          </Stack>
                                        </Collapse>
                                      </>
                                    ) : (
                                      <Typography variant="body2" color="text.secondary">
                                        In diesem Zeitraum fällt noch keine Monatsrate an.
                                      </Typography>
                                    )}
                                  </Stack>
                                ) : null}

                                {requiresManualApproval(expense.amount, approvalThreshold) ? (
                                  <Stack direction="row" gap={1} useFlexGap flexWrap="wrap">
	                                    {requiredApprovalTypes.map((approvalType) => {
                                      const matchingApproval = expense.approvals.find(
                                        (approval) => approval.approvalType === approvalType
                                      );

                                      return (
                                        <Chip
                                          key={approvalType}
                                          label={
                                            matchingApproval
                                              ? `${approvalLabel(approvalType)}: ${matchingApproval.user.name}`
                                              : `${approvalLabel(approvalType)}: offen`
                                          }
                                          color={matchingApproval ? "primary" : "default"}
                                          variant={matchingApproval ? "filled" : "outlined"}
                                          size="small"
                                          sx={wrappingChipSx}
                                        />
                                      );
                                    })}
                                  </Stack>
                                ) : null}

	                                {expense.documents.length > 0 ? (
	                                  <Stack spacing={0.5}>
	                                    {expense.documents.map((document, documentIndex) => (
	                                      <Box key={document.id}>
	                                        <Link
	                                          href={document.proofUrl}
	                                          target="_blank"
	                                          rel="noreferrer"
	                                          underline="hover"
	                                          variant="body2"
	                                          sx={{ overflowWrap: "anywhere" }}
	                                        >
	                                          {`Rechnung ${documentIndex + 1}: ${document.storedFileName}`}
	                                        </Link>
	                                        <Typography variant="caption" color="text.secondary" sx={{ display: "block" }}>
	                                          Rechnung vom {dateFormatter.format(new Date(document.invoiceDate))}
	                                        </Typography>
	                                      </Box>
	                                    ))}
	                                  </Stack>
	                                ) : null}

                                <Stack direction="row" gap={1} useFlexGap flexWrap="wrap">
                                  {availableApprovals.map((approvalType) => (
                                    <Button
                                      key={approvalType}
                                      size="small"
                                      variant="contained"
                                      disabled={busy}
                                      onClick={() => {
                                        if (
                                          !window.confirm(
                                            `Freigabe wirklich setzen?\n\nAusgabe: ${expense.title}\nBetrag: ${formatCurrency(expense.amount)}\nRolle: ${approvalLabel(approvalType)}\n\nMit deiner Freigabe bestätigst du, dass du die Ausgabe plausibel geprüft hast und die Verantwortung für diesen Freigabeschritt übernimmst.`
                                          )
                                        ) {
                                          return;
                                        }

                                        onApprove(expense.id, approvalType);
                                      }}
                                    >
                                      Freigeben als {approvalLabel(approvalType)}
                                    </Button>
                                  ))}

                                  {!expense.paidAt &&
                                  expense.approvalStatus === "APPROVED" &&
                                  canMarkPaid(viewer.role) ? (
                                    <Button
                                      size="small"
                                      variant="outlined"
                                      disabled={busy}
                                      onClick={() => {
                                        if (
                                          !window.confirm(
                                            `Ausgabe "${expense.title}" ohne Rechnung als bezahlt markieren?\n\nNutze das nur für Nachtragungen.`
                                          )
                                        ) {
                                          return;
                                        }

                                        onMarkPaid(expense.id);
                                      }}
                                    >
                                      Ohne Rechnung bezahlt setzen
                                    </Button>
                                  ) : null}

                                  {canDeleteExpense(
                                    viewer.role,
                                    viewer.id,
                                    expense.creator.id,
                                    expense.approvalStatus,
                                    expense.paidAt,
                                    expense.documentedAt
                                  ) ? (
                                    <Button
                                      size="small"
                                      color="error"
                                      variant="outlined"
                                      startIcon={<DeleteOutlineRoundedIcon />}
                                      disabled={busy}
                                      onClick={async () => {
                                        if (!window.confirm(`Ausgabe "${expense.title}" wirklich l\u00f6schen?`)) {
                                          return;
                                        }

                                        await onDeleteExpense(expense.id);
                                      }}
                                    >
                                      {"L\u00f6schen"}
                                    </Button>
                                  ) : null}
                                </Stack>

	                                {expense.approvalStatus === "APPROVED" && canUploadProof ? (
	                                  <Stack spacing={1} sx={{ width: "100%", maxWidth: 420 }}>
	                                    <Stack direction="row" spacing={1}>
	                                      <Button
                                        component="label"
                                        size="small"
                                        variant="outlined"
                                        startIcon={<UploadFileRoundedIcon />}
                                        disabled={busy}
                                        fullWidth
                                        sx={{ minWidth: 0 }}
                                      >
                                        Datei
	                                        <input
	                                          hidden
	                                          type="file"
	                                          multiple
	                                          accept="image/*,application/pdf"
	                                          onChange={(event) => addProofFiles(expense.id, event.target.files)}
	                                        />
	                                      </Button>
                                      <Button
                                        component="label"
                                        size="small"
                                        variant="outlined"
                                        startIcon={<PhotoCameraRoundedIcon />}
                                        disabled={busy}
                                        fullWidth
                                        sx={{ minWidth: 0 }}
                                      >
                                        Kamera
                                        <input
                                          hidden
	                                          type="file"
	                                          accept="image/*"
	                                          capture="environment"
	                                          onChange={(event) => addProofFiles(expense.id, event.target.files)}
	                                        />
	                                      </Button>
	                                    </Stack>
	                                    {(proofFileDrafts[expense.id] ?? []).map((entry, entryIndex) => (
	                                      <Stack key={`${entry.file.name}-${entryIndex}`} spacing={0.7}>
	                                        <Typography variant="caption" color="text.secondary" sx={{ overflowWrap: "anywhere" }}>
	                                          {entry.file.name}
	                                        </Typography>
	                                        <Stack direction={{ xs: "column", sm: "row" }} spacing={1}>
	                                          <TextField
	                                            label="Rechnungsdatum"
	                                            type="date"
	                                            value={entry.invoiceDate}
	                                            onChange={(event) => updateProofInvoiceDate(expense.id, entryIndex, event.target.value)}
	                                            InputLabelProps={{ shrink: true }}
	                                            size="small"
	                                            required
	                                            fullWidth
	                                          />
	                                          <Button
	                                            type="button"
	                                            size="small"
	                                            variant="text"
	                                            color="error"
	                                            onClick={() => removeProofDraft(expense.id, entryIndex)}
	                                          >
	                                            Entfernen
	                                          </Button>
	                                        </Stack>
	                                      </Stack>
	                                    ))}
	                                    <Button
                                      size="medium"
                                      variant="contained"
                                      color="success"
                                      disabled={busy}
                                      fullWidth
                                      sx={{
                                        minHeight: 44,
                                        px: 1.5,
                                        lineHeight: 1.25,
                                        whiteSpace: "normal",
                                        overflowWrap: "anywhere",
                                        textAlign: "center"
                                      }}
                                      onClick={async () => {
	                                        const proofDrafts = proofFileDrafts[expense.id] ?? [];

	                                        if (proofDrafts.length === 0 || proofDrafts.some((entry) => !entry.invoiceDate)) {
	                                          return;
	                                        }

	                                        for (const entry of proofDrafts) {
	                                          await onUploadProof(expense.id, entry.file, entry.invoiceDate);
	                                        }

	                                        setProofFileDrafts((current) => ({
	                                          ...current,
	                                          [expense.id]: []
	                                        }));
	                                      }}
	                                    >
	                                      {expense.paidAt ? "Rechnung nachreichen" : "Rechnung abgeben und bezahlt setzen"}
	                                    </Button>
                                  </Stack>
                                ) : null}

                                <Typography variant="caption" color="text.secondary">
                                  Angelegt am{" "}
                                  {new Intl.DateTimeFormat("de-DE", { dateStyle: "medium", timeStyle: "short" }).format(
                                    new Date(expense.createdAt)
                                  )}
                                </Typography>
                              </Stack>
                            </Box>
                          );
                        })}
                      </Stack>
                    </Stack>
                  </Box>
                </Box>
              );
            })}
          </Box>
        </Stack>
      </CardContent>
    </Card>
  );
}
