import * as fs from 'fs';
import PDFDocument from 'pdfkit-table';

export class PDF {
  public doc;

  constructor(
    path = null,
    options: PDFKit.PDFDocumentOptions = {
      size: 'A4',
      layout: 'landscape',
      margin: 30,
    },
  ) {
    this.doc = new PDFDocument(options);

    const assetsPath = `${__dirname}/../../assets`;

    this.doc.registerFont(
      'Iransans',
      `${assetsPath}/fonts/iransans_medium.ttf`,
    );

    // Pipe its output somewhere, like to a file or HTTP response
    if (path) {
      this.doc.pipe(fs.createWriteStream(path));
    }
  }

  addImage(path, x, y, width) {
    this.doc.image(path, x, y, { width });
  }

  addText(text, x, y, width, fontSize = 9) {
    const fixText = this.fixNumberDirection(text);

    this.doc
      .font('Iransans')
      .fontSize(fontSize)
      .text(fixText || '', x, y, {
        features: ['rtla'],
        align: 'right',
        width,
      });
  }

  async addTable(data, options = {}) {
    const fixData = {
      ...data,
      rows: data.rows.map((row) =>
        row.map((text) => this.fixWordDirection(text)),
      ),
    };
    await this.doc.table(fixData, options);
  }

  addPage() {
    this.doc.addPage();
  }

  end() {
    this.doc.end();
  }

  endBuffer(): Promise<Buffer> {
    return new Promise((resolve) => {
      this.doc.end();

      const buffer = [];

      this.doc.on('data', buffer.push.bind(buffer));

      this.doc.on('end', () => {
        const data = Buffer.concat(buffer);
        resolve(data);
      });
    });
  }

  private fixNumberDirection(text) {
    if (text && !/^[0-9]+$/.test(text)) {
      const match = text.match(/\d+/g);
      if (match?.length) {
        match.forEach((number) => {
          text = text.replace(
            new RegExp(number, 'g'),
            number.split('').reverse().join(''),
          );
        });
      }
    }
    return text;
  }

  private fixWordDirection(text) {
    return text.replace(/\s\s+/g, ' ').split(' ').reverse().join(' ');
  }
}
