import { Op } from 'sequelize';
import sequelize from '../database.js';
import {
  CalendarEvent,
  ClubCommunicationThread,
  ClubInvoice,
  ClubPaymentClaim,
  ClubRequest,
  ClubSepaMandate,
  ClubTask,
  Match,
  Member,
  TrainingGroup,
} from '../models/index.js';
import clubArchiveService from '../services/clubArchiveService.js';
import { hasClubPaymentClaimPaidAmountCentsColumn } from '../services/clubPaymentClaimCompatibility.js';
import { getSafeErrorMessage } from '../utils/errorUtils.js';

function formatRequestWorkflowStage(stage) {
  return {
    contact_replied: 'Kontakt beantwortet',
    trial_training_scheduled: 'Probetraining terminiert',
    trial_training_feedback_recorded: 'Probetraining nachbereitet',
    membership_reviewed: 'Mitgliedsanfrage geprüft',
    admission_prepared: 'Aufnahme vorbereitet',
    member_record_created: 'Mitglied angelegt',
    sepa_pending: 'SEPA ausstehend',
    onboarding_completed: 'Onboarding abgeschlossen',
    sponsoring_contacted: 'Sponsoring kontaktiert',
    sponsoring_offer_prepared: 'Sponsoringangebot vorbereitet',
    sponsoring_followed_up: 'Sponsoring nachgefasst',
  }[stage] || stage;
}

function formatTaskType(taskType) {
  return {
    request_contact_reply: 'Kontaktanfrage beantworten',
    request_schedule_trial_training: 'Probetraining organisieren',
    request_trial_training_follow_up: 'Probetraining nachbereiten',
    request_membership_review: 'Mitgliedsanfrage prüfen',
    membership_prepare_admission: 'Aufnahme vorbereiten',
    membership_create_member_record: 'Mitglied anlegen',
    membership_collect_sepa_mandate: 'SEPA organisieren',
    membership_assign_fee: 'Beitrag zuordnen',
    request_sponsoring_reply: 'Sponsoring nachfassen',
    sponsoring_prepare_offer: 'Sponsoringangebot vorbereiten',
    sponsoring_follow_up: 'Sponsoring nachfassen',
    document_review_required: 'Dokument prüfen',
    sponsor_contract_renewal: 'Sponsoring verlängern',
    member_missing_email: 'E-Mail ergänzen',
    member_missing_birthdate: 'Geburtsdatum ergänzen',
    member_missing_sepa_mandate: 'SEPA-Mandat einholen',
    payment_claim_due_soon: 'Fällige Zahlung vorbereiten',
    payment_claim_overdue: 'Überfällige Zahlung nachfassen',
    payment_claim_reminder: 'Mahnstufe prüfen',
    calendar_event_prepare: 'Termin vorbereiten',
    calendar_event_deadline_check: 'Terminfrist prüfen',
  }[taskType] || taskType || 'Freie Aufgabe';
}

function formatCommunicationStatus(status) {
  return {
    draft: 'Entwurf',
    scheduled: 'Geplant',
    sent: 'Versendet',
    archived: 'Archiviert',
  }[status] || status || 'Status';
}

function formatInvoiceStatus(status) {
  return {
    draft: 'Entwurf',
    issued: 'Gestellt',
    partially_paid: 'Teilbezahlt',
    paid: 'Bezahlt',
    cancelled: 'Storniert',
    archived: 'Archiviert',
  }[status] || status || 'Status';
}

function formatEventDateRange(event) {
  if (!event?.startDate) {
    return null;
  }

  const formatter = new Intl.DateTimeFormat('de-DE', { dateStyle: 'medium' });
  const start = formatter.format(new Date(event.startDate));
  const end = event.endDate ? formatter.format(new Date(event.endDate)) : start;
  return start === end ? start : `${start} bis ${end}`;
}

function formatDate(value, options = { dateStyle: 'medium' }) {
  if (!value) {
    return null;
  }

  return new Intl.DateTimeFormat('de-DE', options).format(new Date(value));
}

function formatTime(value) {
  if (!value) {
    return null;
  }

  return String(value).slice(0, 5);
}

function formatWeekday(weekday) {
  return ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'][Number(weekday)] || 'Unbekannt';
}

function formatConfiguredTrainingLabel(entry) {
  const start = formatTime(entry.startTime);
  const end = formatTime(entry.endTime);
  const timeRange = start && end ? `${start} bis ${end} Uhr` : start ? `${start} Uhr` : null;

  return [entry.groupName, formatWeekday(entry.weekday), timeRange].filter(Boolean).join(' · ');
}

function formatMatchLabel(match) {
  const date = formatDate(match.date);
  const time = formatTime(match.time);
  const homeTeam = match.homeTeam?.name || 'Heimteam';
  const guestTeam = match.guestTeam?.name || 'Gastteam';
  const league = match.leagueDetails?.name || null;

  return [
    `${homeTeam} gegen ${guestTeam}`,
    date,
    time ? `${time} Uhr` : null,
    league,
  ].filter(Boolean).join(' · ');
}

function createDashboardItem(label, to, extra = {}) {
  return { label, to, ...extra };
}

function buildMemberRoute(memberId, scope = 'active', extraQuery = {}) {
  return {
    path: '/members',
    query: {
      scope,
      memberId: String(memberId),
      mode: 'edit',
      ...extraQuery,
    },
  };
}

function buildRequestRoute(requestId, status = '') {
  const query = { requestId: String(requestId) };
  if (status) {
    query.status = status;
  }
  return {
    path: '/club-requests',
    query,
  };
}

function buildTaskRoute(taskId, status = '') {
  const query = { taskId: String(taskId) };
  if (status) {
    query.status = status;
  }
  return {
    path: '/club-tasks',
    query,
  };
}

async function loadAvailableTables() {
  const tables = await sequelize.getQueryInterface().showAllTables();
  return new Set(
    tables
      .map((table) => (typeof table === 'string' ? table : Object.values(table || {})[0]))
      .filter(Boolean)
      .map((table) => String(table).toLowerCase())
  );
}

async function loadOptionalTableData(availableTables, tableName, loader, fallbackValue = []) {
  if (!availableTables.has(String(tableName).toLowerCase())) {
    return fallbackValue;
  }

  return loader();
}

function countMissingMemberFields(members) {
  const missing = {
    email: 0,
    birthDate: 0,
  };

  for (const member of members) {
    if (!String(member.email || '').trim()) {
      missing.email += 1;
    }
    if (!String(member.birthDate || '').trim()) {
      missing.birthDate += 1;
    }
  }

  return missing;
}

function toNextOccurrenceDate(weekday, startTime) {
  const now = new Date();
  const result = new Date(now);
  const targetWeekday = Number(weekday);
  const daysUntilWeekday = (targetWeekday - result.getDay() + 7) % 7;
  result.setDate(result.getDate() + daysUntilWeekday);

  const [hours = '0', minutes = '0'] = String(startTime || '00:00').split(':');
  result.setHours(Number(hours), Number(minutes), 0, 0);

  if (result < now) {
    result.setDate(result.getDate() + 7);
  }

  return result;
}

function buildUpcomingTrainingSlots(groups, limit = 5) {
  return groups
    .flatMap((group) => (Array.isArray(group.trainingTimes) ? group.trainingTimes.map((time) => ({
      id: time.id,
      weekday: time.weekday,
      startTime: time.startTime,
      endTime: time.endTime,
      sortOrder: time.sortOrder,
      groupName: group.name,
      nextOccurrence: toNextOccurrenceDate(time.weekday, time.startTime),
    })) : []))
    .sort((left, right) => {
      const timeDiff = left.nextOccurrence.getTime() - right.nextOccurrence.getTime();
      if (timeDiff !== 0) return timeDiff;
      return String(left.groupName || '').localeCompare(String(right.groupName || ''));
    })
    .slice(0, limit);
}

export const getClubDashboard = async (req, res) => {
  try {
    const clubId = Number(req.params.clubId);
    const currentUserId = Number(req.user?.id) || null;
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const todayIso = today.toISOString().slice(0, 10);
    const availableTables = await loadAvailableTables();
    const hasPaidAmountCentsColumn = await hasClubPaymentClaimPaidAmountCentsColumn();

    const [
      requests,
      tasks,
      members,
      mandates,
      paymentClaims,
      upcomingEvents,
      trainingGroups,
      upcomingMatches,
      communicationThreads,
      invoices,
      archive,
    ] = await Promise.all([
      loadOptionalTableData(availableTables, 'club_requests', () => ClubRequest.findAll({
        where: {
          clubId,
          status: { [Op.notIn]: ['archived'] },
        },
        order: [['receivedAt', 'DESC']],
      })),
      loadOptionalTableData(availableTables, 'club_tasks', () => ClubTask.findAll({
        where: {
          clubId,
          status: { [Op.notIn]: ['archived'] },
        },
        order: [['dueAt', 'ASC'], ['updatedAt', 'DESC']],
      })),
      Member.findAll({
        where: {
          clubId,
          active: true,
        },
        order: [['createdAt', 'DESC']],
      }),
      loadOptionalTableData(availableTables, 'club_sepa_mandates', () => ClubSepaMandate.findAll({
        where: {
          clubId,
          status: 'active',
          revokedAt: null,
          memberId: { [Op.ne]: null },
        },
        attributes: ['memberId'],
      })),
      hasPaidAmountCentsColumn
        ? loadOptionalTableData(availableTables, 'club_payment_claims', () => ClubPaymentClaim.findAll({
          where: {
            clubId,
            status: { [Op.in]: ['open', 'partially_paid'] },
            archivedAt: null,
          },
          order: [['dueOn', 'ASC']],
        }))
        : Promise.resolve([]),
      loadOptionalTableData(availableTables, 'calendar_events', () => CalendarEvent.findAll({
        where: {
          clubId,
          endDate: { [Op.gte]: todayIso },
        },
        order: [['startDate', 'ASC']],
        limit: 5,
      })),
      loadOptionalTableData(availableTables, 'training_group', () => TrainingGroup.findAll({
        where: {
          clubId,
        },
        include: [
          {
            association: 'trainingTimes',
            required: false,
          },
        ],
        order: [['isPreset', 'DESC'], ['sortOrder', 'ASC'], ['name', 'ASC']],
      })),
      loadOptionalTableData(availableTables, 'match', () => Match.findAll({
        where: {
          clubId,
          date: { [Op.gte]: today },
        },
        include: [
          { association: 'homeTeam', attributes: ['id', 'name'] },
          { association: 'guestTeam', attributes: ['id', 'name'] },
          { association: 'leagueDetails', attributes: ['id', 'name'] },
        ],
        order: [['date', 'ASC'], ['time', 'ASC']],
        limit: 5,
      })),
      loadOptionalTableData(availableTables, 'club_communication_threads', () => ClubCommunicationThread.findAll({
        where: { clubId },
        attributes: ['id', 'subject', 'status', 'threadType', 'scheduledAt', 'sentAt', 'updatedAt'],
        order: [['updatedAt', 'DESC'], ['createdAt', 'DESC']],
        limit: 8,
      })),
      loadOptionalTableData(availableTables, 'club_invoices', () => ClubInvoice.findAll({
        where: {
          clubId,
          archivedAt: null,
        },
        attributes: ['id', 'invoiceNumber', 'invoiceDirection', 'invoiceType', 'status', 'dueOn', 'grossAmountCents', 'currencyCode', 'updatedAt'],
        order: [['updatedAt', 'DESC'], ['dueOn', 'ASC']],
        limit: 8,
      })),
      clubArchiveService.getClubArchive(clubId),
    ]);

    const visibleDashboardTasks = tasks.filter((task) => !task.assignedUserId || Number(task.assignedUserId) === currentUserId);
    const membersById = new Map(members.map((member) => [Number(member.id), member]));
    const paymentClaimsById = new Map(paymentClaims.map((claim) => [Number(claim.id), claim]));
    const missingFields = countMissingMemberFields(members);
    const openTasks = visibleDashboardTasks.filter((task) => task.status === 'open');
    const inProgressTasks = visibleDashboardTasks.filter((task) => task.status === 'in_progress');
    const automatedTasks = visibleDashboardTasks.filter((task) => Boolean(task.automationKey));
    const automatedOpenTasks = automatedTasks.filter((task) => ['open', 'in_progress', 'waiting'].includes(task.status));
    const overdueTaskCount = visibleDashboardTasks.filter((task) => {
      if (!task.dueAt || ['done', 'cancelled', 'archived'].includes(task.status)) {
        return false;
      }
      return new Date(task.dueAt) < today;
    }).length;
    const memberIdsWithMandate = new Set(mandates.map((mandate) => Number(mandate.memberId)).filter(Boolean));
    const missingMandateCount = members.filter((member) => !memberIdsWithMandate.has(Number(member.id))).length;
    const openRequestCount = requests.filter((request) => request.status === 'open').length;
    const inProgressRequestCount = requests.filter((request) => request.status === 'in_progress').length;
    const trialTrainingCount = requests.filter((request) => request.requestType === 'trial_training' && request.status !== 'archived').length;
    const workflowStageCounts = requests.reduce((accumulator, request) => {
      if (!request.workflowStage) return accumulator;
      accumulator[request.workflowStage] = (accumulator[request.workflowStage] || 0) + 1;
      return accumulator;
    }, {});
    const onboardingCount =
      (workflowStageCounts.membership_reviewed || 0) +
      (workflowStageCounts.admission_prepared || 0) +
      (workflowStageCounts.member_record_created || 0) +
      (workflowStageCounts.sepa_pending || 0);
    const duePaymentCount = paymentClaims.filter((claim) => claim.status === 'open').length;
    const reminderCount = paymentClaims.filter((claim) => Number(claim.reminderLevel || 0) > 0).length;
    const openInvoices = invoices.filter((invoice) => ['draft', 'issued', 'partially_paid'].includes(invoice.status));
    const outgoingOpenInvoices = openInvoices.filter((invoice) => invoice.invoiceDirection === 'outgoing');
    const incomingOpenInvoices = openInvoices.filter((invoice) => invoice.invoiceDirection === 'incoming');
    const communicationDraftCount = communicationThreads.filter((thread) => thread.status === 'draft').length;
    const communicationScheduledCount = communicationThreads.filter((thread) => thread.status === 'scheduled').length;
    const communicationSentCount = communicationThreads.filter((thread) => thread.status === 'sent').length;
    const recentMembers = members.slice(0, 4);
    const upcomingTrainings = buildUpcomingTrainingSlots(trainingGroups);
    const paidRatio = paymentClaims.length === 0
      ? null
      : Math.max(
        0,
        Math.round(
          ((paymentClaims.length - duePaymentCount) / paymentClaims.length) * 100
        )
      );

    function taskDetailTarget(task) {
      if (task.relatedEntityType === 'member' && task.relatedEntityId) {
        return buildMemberRoute(task.relatedEntityId, 'active');
      }

      if (task.relatedEntityType === 'club_request' && task.relatedEntityId) {
        const request = requests.find((entry) => Number(entry.id) === Number(task.relatedEntityId));
        return buildRequestRoute(task.relatedEntityId, request?.status || '');
      }

      if (task.relatedEntityType === 'club_payment_claim' && task.relatedEntityId) {
        const claim = paymentClaimsById.get(Number(task.relatedEntityId));
        if (claim?.memberId) {
          return buildMemberRoute(claim.memberId, 'active');
        }
      }

      return buildTaskRoute(task.id, task.status || '');
    }

    function taskDashboardItem(task, label) {
      return createDashboardItem(label, taskDetailTarget(task), {
        isAssignedToCurrentUser: Boolean(task.assignedUserId) && Number(task.assignedUserId) === currentUserId,
      });
    }

    const sections = [
      {
        id: 'action-needed',
        title: 'Handlungsbedarf',
        cards: [
          {
            title: 'Neue Anfragen',
            value: `${openRequestCount + inProgressRequestCount}`,
            meta: trialTrainingCount > 0 ? `${trialTrainingCount} Probetrainings` : null,
            to: '/club-requests',
            accent: 'amber',
            items: [
              createDashboardItem(`${openRequestCount} offen`, '/club-requests'),
              createDashboardItem(`${inProgressRequestCount} in Bearbeitung`, '/club-requests'),
            ],
          },
          {
            title: 'Anfrage-Workflows',
            value: `${onboardingCount}`,
            meta: onboardingCount > 0 ? 'im Aufnahme- und Onboardingprozess' : 'Keine aktiven Onboarding-Fälle',
            to: '/club-requests',
            accent: 'green',
            items: [
              createDashboardItem(`${workflowStageCounts.trial_training_scheduled || 0} Probetrainings terminiert`, '/club-requests'),
              createDashboardItem(`${workflowStageCounts.membership_reviewed || 0} Mitgliedsanfragen geprüft`, '/club-requests'),
              createDashboardItem(`${workflowStageCounts.sepa_pending || 0} Fälle mit ausstehendem SEPA`, '/club-requests'),
            ],
          },
          {
            title: 'Offene Zahlungen',
            value: `${paymentClaims.length}`,
            meta: [
              duePaymentCount > 0 ? `${duePaymentCount} fällig offen` : null,
              reminderCount > 0 ? `${reminderCount} mit Mahnstufe` : null,
            ].filter(Boolean).join(' · ') || 'Keine Mahnungen aktiv',
            to: '/club-payments',
            accent: 'red',
            items: paymentClaims.slice(0, 3).map((claim) => {
              const amount = `${(Number(claim.amountCents) / 100).toFixed(2)} ${claim.currencyCode || 'EUR'}`;
              return createDashboardItem(
                `${amount} · ${claim.dueOn ? `fällig ${claim.dueOn}` : 'ohne Fälligkeit'}`,
                claim.memberId ? buildMemberRoute(claim.memberId, 'active') : '/club-payments'
              );
            }),
          },
          {
            title: 'Fehlende Daten',
            value: `${missingFields.email + missingFields.birthDate + missingMandateCount}`,
            to: '/members',
            accent: 'blue',
            items: [
              createDashboardItem(`${missingFields.email} Mitglieder ohne E-Mail`, { path: '/members', query: { scope: 'dataIncomplete' } }),
              createDashboardItem(`${missingFields.birthDate} Mitglieder ohne Geburtsdatum`, { path: '/members', query: { scope: 'dataIncomplete' } }),
              createDashboardItem(`${missingMandateCount} Mitglieder ohne SEPA-Mandat`, { path: '/members', query: { scope: 'dataIncomplete' } }),
            ],
          },
          {
            title: 'Offene Aufgaben',
            value: `${openTasks.length + inProgressTasks.length}`,
            meta: overdueTaskCount > 0 ? `${overdueTaskCount} überfällig` : 'Keine überfälligen Aufgaben',
            to: '/club-tasks',
            accent: overdueTaskCount > 0 ? 'red' : 'green',
            items: [
              createDashboardItem(`${automatedOpenTasks.length} automatisch erzeugte Schritte`, '/club-tasks'),
              ...visibleDashboardTasks.slice(0, 3).map((task) => taskDashboardItem(task, task.title)),
            ],
          },
        ],
      },
      {
        id: 'operations-room',
        title: 'Kommunikation, Finanzen und Archiv',
        cards: [
          {
            title: 'Kommunikation',
            value: `${communicationThreads.length}`,
            meta: `${communicationDraftCount} Entwürfe, ${communicationScheduledCount} geplant, ${communicationSentCount} versendet`,
            to: '/club-communication',
            accent: 'blue',
            items: communicationThreads.slice(0, 3).map((thread) => createDashboardItem(
              `${thread.subject || 'Ohne Betreff'} · ${formatCommunicationStatus(thread.status)}`,
              '/club-communication'
            )),
          },
          {
            title: 'Rechnungen',
            value: `${openInvoices.length}`,
            meta: `${outgoingOpenInvoices.length} ausgehend, ${incomingOpenInvoices.length} eingehend`,
            to: '/club-invoices',
            accent: 'amber',
            items: openInvoices.slice(0, 3).map((invoice) => createDashboardItem(
              `${invoice.invoiceNumber || `Rechnung #${invoice.id}`} · ${formatInvoiceStatus(invoice.status)}`,
              '/club-invoices'
            )),
          },
          {
            title: 'Archiv',
            value: `${archive.summary.archivedRequests + archive.summary.archivedTasks + archive.summary.archivedClaims}`,
            meta: `${archive.summary.inactiveMembers} inaktive Mitglieder`,
            to: '/club-archive',
            accent: 'neutral',
            items: [
              createDashboardItem(`${archive.summary.archivedRequests} archivierte Anfragen`, '/club-archive'),
              createDashboardItem(`${archive.summary.archivedTasks} archivierte Aufgaben`, '/club-archive'),
              createDashboardItem(`${archive.summary.archivedClaims} archivierte Beitragsfälle`, '/club-archive'),
            ],
          },
        ],
      },
      {
        id: 'appointments',
        title: 'Aktuelle Termine',
        cards: [
          {
            title: 'Nächste Trainings',
            value: `${upcomingTrainings.length}`,
            to: {
              path: '/club-settings',
              query: { tab: 'training-times' },
            },
            items: upcomingTrainings.map((training) => createDashboardItem(
              formatConfiguredTrainingLabel(training),
              {
                path: '/club-settings',
                query: { tab: 'training-times' },
              }
            )),
          },
          {
            title: 'Nächste Spiele',
            value: `${upcomingMatches.length}`,
            to: '/schedule',
            items: upcomingMatches.map((match) => createDashboardItem(formatMatchLabel(match), '/schedule')),
          },
          {
            title: 'Kalendertermine',
            value: `${upcomingEvents.length}`,
            to: '/calendar',
            items: upcomingEvents.map((event) => createDashboardItem(`${event.title} · ${formatEventDateRange(event)}`, '/calendar')),
          },
        ],
      },
      {
        id: 'club-status',
        title: 'Vereinsstatus',
        cards: [
          {
            title: 'Mitglieder',
            value: `${members.length} aktiv`,
            meta: members.length > 0 ? `${members.filter((member) => {
              const createdAt = new Date(member.createdAt);
              return createdAt.getFullYear() === today.getFullYear();
            }).length} dieses Jahr angelegt` : null,
            to: '/members',
            items: recentMembers.map((member) => {
              const name = [member.firstName, member.lastName].filter(Boolean).join(' ').trim() || member.email || `Mitglied ${member.id}`;
              return createDashboardItem(name, buildMemberRoute(member.id, 'active'));
            }),
          },
          {
            title: 'Anfragen',
            value: `${requests.length}`,
            meta: `${openRequestCount} offen, ${inProgressRequestCount} in Bearbeitung`,
            to: '/club-requests',
          },
          {
            title: 'Workflow-Fortschritt',
            value: `${workflowStageCounts.onboarding_completed || 0}`,
            meta: 'Onboardings abgeschlossen',
            to: '/club-requests',
            items: [
              createDashboardItem(`${workflowStageCounts.admission_prepared || 0} Aufnahmen vorbereitet`, '/club-requests'),
              createDashboardItem(`${workflowStageCounts.member_record_created || 0} Mitglieder angelegt`, '/club-requests'),
              createDashboardItem(`${workflowStageCounts.sepa_pending || 0} warten auf SEPA`, '/club-requests'),
            ],
          },
          {
            title: 'Finanzen',
            value: paidRatio === null ? 'Keine Daten' : `${paidRatio} % erledigt`,
            meta: paymentClaims.length > 0 ? `${paymentClaims.length} offene oder teilweise offene Forderungen` : 'Noch keine Beitragsforderungen erfasst',
            to: '/club-tasks',
          },
        ],
      },
      {
        id: 'recent-activity',
        title: 'Letzte Aktivitäten',
        cards: [
          {
            title: 'Zuletzt eingegangen',
            to: '/club-requests',
            items: requests.slice(0, 4).map((request) => {
              const name = [request.firstName, request.lastName].filter(Boolean).join(' ').trim() || request.email || 'Unbekannt';
              const workflow = request.workflowStage ? ` · ${formatRequestWorkflowStage(request.workflowStage)}` : '';
              return createDashboardItem(
                `${name} · ${request.subject || request.requestType}${workflow}`,
                buildRequestRoute(request.id, request.status || '')
              );
            }),
          },
          {
            title: 'Aktuelle Aufgaben',
            to: '/club-tasks',
            items: visibleDashboardTasks.slice(0, 4).map((task) => taskDashboardItem(task, `${formatTaskType(task.taskType)} · ${task.status}`)),
          },
          {
            title: 'Automatik zuletzt aktiv',
            to: '/club-tasks',
            items: automatedTasks.slice(0, 4).map((task) => {
              const sourceLabel = task.automationSource === 'club_requests'
                ? 'Anfrage'
                : task.automationSource === 'club_payment_claims'
                  ? 'Zahlung'
                  : task.automationSource === 'club_documents'
                    ? 'Dokument'
                    : task.automationSource === 'club_invoice_parties'
                      ? 'Sponsor'
                      : task.automationSource === 'club_invoices'
                        ? 'Rechnung'
                        : task.automationSource === 'club_communication'
                          ? 'Kommunikation'
                          : task.automationSource === 'calendar_events'
                            ? 'Termin'
                            : 'Workflow';
              return taskDashboardItem(task, `${formatTaskType(task.taskType)} · ${sourceLabel}`);
            }),
          },
        ],
      },
    ];

    res.status(200).json({ sections });
  } catch (error) {
    console.error('[getClubDashboard] - Error:', error);
    res.status(error.statusCode || 500).json({
      error: getSafeErrorMessage(error, 'Dashboard konnte nicht geladen werden.'),
    });
  }
};
