import { Injectable } from '@nestjs/common';
import PDFDocument = require('pdfkit');

export interface ReceiptData {
  receiptNo: string;
  paidAt: Date;
  complexName: string;
  lotNumber: string;
  residentName: string;
  amount: number;
  currency: string;
  method: string;
  reference?: string;
  period?: string;
}

export interface FormalNoticeData {
  noticeNo: string;
  issuedAt: Date;
  complexName: string;
  lotNumber: string;
  residentName: string;
  residentAddress?: string;
  totalDue: number;
  penalty: number;
  currency: string;
  dueDate: Date;
  syndicName: string;
}

export interface PvAssemblyData {
  assemblyTitle: string;
  heldAt: Date;
  location?: string;
  complexName: string;
  resolutions: {
    title: string;
    text: string;
    majority: string;
    status: string;
    votesFor: number;
    votesAgainst: number;
    votesAbstain: number;
  }[];
}

@Injectable()
export class PdfService {
  /** Generate a buffer with a payment receipt */
  async generateReceipt(data: ReceiptData): Promise<Buffer> {
    return this.render((doc) => {
      this.header(doc, 'REÇU DE PAIEMENT / RECEIPT', data.complexName);
      doc.fontSize(11).font('Helvetica');
      doc.moveDown().text(`N° reçu / Receipt No : ${data.receiptNo}`);
      doc.text(`Date : ${data.paidAt.toISOString().slice(0, 10)}`);
      doc.moveDown();
      doc.text(`Bénéficiaire : ${data.residentName}`);
      doc.text(`Lot : ${data.lotNumber}`);
      if (data.period) doc.text(`Période : ${data.period}`);
      doc.moveDown();
      doc.fontSize(13).font('Helvetica-Bold');
      doc.text(`Montant payé : ${data.amount.toFixed(2)} ${data.currency}`);
      doc.fontSize(11).font('Helvetica');
      doc.text(`Mode de paiement : ${data.method}`);
      if (data.reference) doc.text(`Référence : ${data.reference}`);
      doc.moveDown().moveDown();
      doc.fontSize(9).fillColor('#666').text(
        'Ce reçu a été généré automatiquement par SyndiClub. Conservez-le pour vos archives.',
      );
    });
  }

  async generateFormalNotice(data: FormalNoticeData): Promise<Buffer> {
    return this.render((doc) => {
      this.header(doc, 'MISE EN DEMEURE', data.complexName);
      doc.fontSize(10).font('Helvetica');
      doc.moveDown().text(`N° : ${data.noticeNo}`);
      doc.text(`Date d'émission : ${data.issuedAt.toISOString().slice(0, 10)}`);
      doc.moveDown();
      doc.text(`À l'attention de : ${data.residentName}`);
      if (data.residentAddress) doc.text(data.residentAddress);
      doc.text(`Lot concerné : ${data.lotNumber}`);
      doc.moveDown();
      doc.font('Helvetica-Bold').text('Objet : Mise en demeure de payer');
      doc.moveDown();
      doc.font('Helvetica').fontSize(11);
      doc.text(
        `Madame, Monsieur,\n\nMalgré nos précédentes relances, nous constatons que votre compte présente un impayé au titre des charges de copropriété du complexe « ${data.complexName} ».`,
        { align: 'justify' },
      );
      doc.moveDown();
      doc.text(`Montant principal dû : ${data.totalDue.toFixed(2)} ${data.currency}`);
      doc.text(`Pénalités de retard : ${data.penalty.toFixed(2)} ${data.currency}`);
      doc.font('Helvetica-Bold').text(
        `TOTAL à régler : ${(data.totalDue + data.penalty).toFixed(2)} ${data.currency}`,
      );
      doc.moveDown();
      doc.font('Helvetica').text(
        `Nous vous mettons en demeure de procéder au règlement de cette somme au plus tard le ${data.dueDate
          .toISOString()
          .slice(0, 10)}, sous peine d'engager les procédures de recouvrement contentieux prévues par la loi.`,
        { align: 'justify' },
      );
      doc.moveDown().moveDown();
      doc.text(`Fait pour servir et valoir ce que de droit.`);
      doc.moveDown();
      doc.text(`Le Syndic — ${data.syndicName}`);
    });
  }

  async generatePvAssembly(data: PvAssemblyData): Promise<Buffer> {
    return this.render((doc) => {
      this.header(doc, `PROCÈS-VERBAL D'ASSEMBLÉE GÉNÉRALE`, data.complexName);
      doc.fontSize(11).font('Helvetica');
      doc.moveDown().text(`Objet : ${data.assemblyTitle}`);
      doc.text(`Tenue le : ${data.heldAt.toISOString().slice(0, 10)}`);
      if (data.location) doc.text(`Lieu : ${data.location}`);
      doc.moveDown();
      doc.font('Helvetica-Bold').text('RÉSOLUTIONS ADOPTÉES');
      doc.font('Helvetica');
      data.resolutions.forEach((r, i) => {
        doc.moveDown();
        doc.font('Helvetica-Bold').text(`Résolution ${i + 1} — ${r.title}`);
        doc.font('Helvetica').fontSize(10).text(r.text, { align: 'justify' });
        doc.fontSize(9).fillColor('#444').text(
          `Majorité requise : ${r.majority} — Résultat : ${r.status}`,
        );
        doc.text(
          `Pour : ${r.votesFor.toFixed(2)} / Contre : ${r.votesAgainst.toFixed(2)} / Abstention : ${r.votesAbstain.toFixed(2)}`,
        );
        doc.fillColor('black').fontSize(11);
      });
      doc.moveDown().moveDown();
      doc.text('Signé par le Président de séance et le Secrétaire.');
    });
  }

  // ---------- internal helpers ----------

  private header(doc: PDFKit.PDFDocument, title: string, complex: string) {
    doc.fontSize(16).font('Helvetica-Bold').text('SyndiClub', { align: 'right' });
    doc.fontSize(9).font('Helvetica').fillColor('#666').text('Plateforme de gestion de copropriété', {
      align: 'right',
    });
    doc.fillColor('black').moveDown();
    doc.fontSize(16).font('Helvetica-Bold').text(title, { align: 'center' });
    doc.fontSize(11).font('Helvetica').text(complex, { align: 'center' });
    doc.moveTo(50, doc.y + 5).lineTo(545, doc.y + 5).stroke();
    doc.moveDown();
  }

  private render(build: (doc: PDFKit.PDFDocument) => void): Promise<Buffer> {
    return new Promise((resolve) => {
      const doc = new PDFDocument({ size: 'A4', margin: 50 });
      const chunks: Buffer[] = [];
      doc.on('data', (c: Buffer) => chunks.push(c));
      doc.on('end', () => resolve(Buffer.concat(chunks)));
      build(doc);
      doc.end();
    });
  }
}
