import { Op } from 'sequelize';
import sequelize from '../database.js';
import { ClubPaymentClaim, ClubRequest, ClubTask, Member } from '../models/index.js';
import { hasClubPaymentClaimPaidAmountCentsColumn } from './clubPaymentClaimCompatibility.js';

const DEFAULT_LIMIT = 50;

function formatMemberName(member) {
  return [member?.firstName, member?.lastName].filter(Boolean).join(' ').trim() || `Mitglied #${member?.id}`;
}

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();
}

class ClubArchiveService {
  async getClubArchive(clubIdRaw) {
    const clubId = Number.parseInt(clubIdRaw, 10);
    if (!Number.isFinite(clubId)) {
      const error = new Error('Ungültige clubId');
      error.status = 400;
      throw error;
    }

    const availableTables = await loadAvailableTables();
    const hasPaidAmountCentsColumn = await hasClubPaymentClaimPaidAmountCentsColumn();

    const members = await Member.findAll({
      where: { clubId },
      order: [['updatedAt', 'DESC'], ['createdAt', 'DESC']],
    });

    const memberMap = new Map(members.map((member) => [Number(member.id), member]));

    const archivedRequests = await loadOptionalTableData(
      availableTables,
      'club_requests',
      () => ClubRequest.findAll({
        where: {
          clubId,
          status: 'archived',
        },
        order: [['updatedAt', 'DESC'], ['createdAt', 'DESC']],
        limit: DEFAULT_LIMIT,
      })
    );

    const archivedTasks = await loadOptionalTableData(
      availableTables,
      'club_tasks',
      () => ClubTask.findAll({
        where: {
          clubId,
          status: 'archived',
        },
        order: [['archivedAt', 'DESC'], ['updatedAt', 'DESC']],
        limit: DEFAULT_LIMIT,
      })
    );

    const archivedClaims = hasPaidAmountCentsColumn
      ? await loadOptionalTableData(
        availableTables,
        'club_payment_claims',
        () => ClubPaymentClaim.findAll({
          where: {
            clubId,
            [Op.or]: [
              { archivedAt: { [Op.not]: null } },
              { status: { [Op.in]: ['written_off', 'cancelled'] } },
            ],
          },
          order: [['archivedAt', 'DESC'], ['updatedAt', 'DESC']],
          limit: DEFAULT_LIMIT,
        })
      )
      : [];

    const inactiveMembers = members
      .filter((member) => !member.active)
      .slice(0, DEFAULT_LIMIT)
      .map((member) => ({
        id: member.id,
        firstName: member.firstName || '',
        lastName: member.lastName || '',
        displayName: formatMemberName(member),
        email: member.email || '',
        city: member.city || '',
        createdAt: member.createdAt || null,
        updatedAt: member.updatedAt || null,
      }));

    return {
      summary: {
        inactiveMembers: members.filter((member) => !member.active).length,
        archivedRequests: archivedRequests.length,
        archivedTasks: archivedTasks.length,
        archivedClaims: archivedClaims.length,
      },
      inactiveMembers,
      archivedRequests: archivedRequests.map((entry) => ({
        id: entry.id,
        requestType: entry.requestType,
        status: entry.status,
        subject: entry.subject || '',
        personName: [entry.firstName, entry.lastName].filter(Boolean).join(' ').trim(),
        email: entry.email || '',
        updatedAt: entry.updatedAt || null,
        createdAt: entry.createdAt || null,
      })),
      archivedTasks: archivedTasks.map((entry) => ({
        id: entry.id,
        title: entry.title || '',
        taskType: entry.taskType || '',
        status: entry.status,
        priority: entry.priority || 'normal',
        dueAt: entry.dueAt || null,
        archivedAt: entry.archivedAt || null,
        updatedAt: entry.updatedAt || null,
      })),
      archivedClaims: archivedClaims.map((entry) => {
        const member = memberMap.get(Number(entry.memberId));
        return {
          id: entry.id,
          memberId: entry.memberId || null,
          memberName: member ? formatMemberName(member) : '',
          claimType: entry.claimType || 'membership_fee',
          status: entry.status,
          dueOn: entry.dueOn || null,
          amountCents: Number(entry.amountCents || 0),
          currencyCode: entry.currencyCode || 'EUR',
          settledAt: entry.settledAt || null,
          archivedAt: entry.archivedAt || null,
          updatedAt: entry.updatedAt || null,
        };
      }),
      notes: [
        'Das Vereinsarchiv zeigt inaktive Mitglieder sowie archivierte oder abgeschlossene Vereinsvorgänge.',
        'Ein zentrales Dokumentenarchiv wird ergänzt, sobald Dokumente und Rechnungen produktiv archiviert werden.',
      ],
    };
  }
}

export default new ClubArchiveService();
