import { Team } from 'src/teams/entities/team.entity';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const PDFDocument = require('pdfkit');

export interface CashboxExportRow {
  date: string;
  type: string;
  who: string;
  note: string;
  amount: number;
  runningTotal: number;
}

interface RawRow {
  date: string;
  type: string;
  who: string;
  note: string;
  amount: number;
}

export function buildRows(team: Team, from: string, to: string): CashboxExportRow[] {
  const fromTime = new Date(`${from}T00:00:00.000Z`).getTime();
  const toTime = new Date(`${to}T23:59:59.999Z`).getTime();

  const raw: RawRow[] = [];

  for (const transaction of team.transactions ?? []) {
    if (!transaction.type) continue;
    raw.push({
      date: transaction.date,
      type: transaction.type.name,
      who: 'Teamkasse',
      note: transaction.note,
      amount: Number(transaction.amount),
    });
  }

  for (const player of team.players ?? []) {
    for (const transaction of player.transactions ?? []) {
      if (!transaction.type || transaction.type.name !== 'payment') continue;
      raw.push({
        date: transaction.date,
        type: transaction.type.name,
        who: `${player.firstName} ${player.lastName}`,
        note: transaction.note,
        amount: Number(transaction.amount),
      });
    }
  }

  const filtered = raw
    .filter((row) => {
      const time = new Date(row.date).getTime();
      return time >= fromTime && time <= toTime;
    })
    .sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));

  let runningTotal = 0;
  return filtered.map((row) => {
    runningTotal += row.amount;
    return { ...row, runningTotal };
  });
}

const TYPE_LABELS: Record<string, string> = {
  payment: 'Zahlung',
  credit: 'Guthaben',
  expense: 'Ausgabe',
};

function formatGermanAmount(value: number): string {
  const rounded = Math.sign(value) * Math.round((Math.abs(value) + Number.EPSILON) * 100) / 100;
  const normalized = rounded === 0 ? 0 : rounded;
  return normalized.toFixed(2).replace('.', ',');
}

function escapeCsvField(value: string): string {
  if (/[;"\n\r]/.test(value)) {
    return `"${value.replace(/"/g, '""')}"`;
  }
  return value;
}

export function buildCsv(rows: CashboxExportRow[]): string {
  const lines = ['Datum;Typ;Wer;Notiz;Betrag;Periodensaldo'];
  if (rows.length === 0) {
    lines.push('Keine Buchungen im gewählten Zeitraum');
  } else {
    for (const row of rows) {
      lines.push(
        [
          row.date.slice(0, 10),
          TYPE_LABELS[row.type] ?? row.type,
          escapeCsvField(row.who),
          escapeCsvField(row.note),
          formatGermanAmount(row.amount),
          formatGermanAmount(row.runningTotal),
        ].join(';'),
      );
    }
  }
  return lines.join('\r\n');
}

export function buildPdf(
  team: Pick<Team, 'name'>,
  rows: CashboxExportRow[],
  from: string,
  to: string,
): Promise<Buffer> {
  return new Promise((resolve, reject) => {
    const doc = new PDFDocument({ margin: 40 });
    const chunks: Buffer[] = [];
    doc.on('data', (chunk) => chunks.push(chunk));
    doc.on('end', () => resolve(Buffer.concat(chunks)));
    doc.on('error', reject);

    doc.fontSize(16).text(`Kassenbuch ${team.name}`);
    doc.fontSize(10).text(`Zeitraum: ${from} bis ${to}`);
    doc.moveDown();

    if (rows.length === 0) {
      doc.text('Keine Buchungen im gewählten Zeitraum.');
    } else {
      for (const row of rows) {
        doc.text(
          `${row.date.slice(0, 10)}  ${TYPE_LABELS[row.type] ?? row.type}  ${row.who}  ${row.note}  ` +
            `${formatGermanAmount(row.amount)} €  Saldo: ${formatGermanAmount(row.runningTotal)} €`,
        );
      }
    }

    doc.end();
  });
}
