import { Injectable } from '@nestjs/common';
import * as fs from 'fs';
import * as path from 'path';

const PDFDocument = require('pdfkit');

// ── Brand ──────────────────────────────────────────────
const B = {
  black: '#000000',
  white: '#FFFFFF',
  gray50: '#F8F9FB',
  gray200: '#E5E7EB',
  gray500: '#6B7280',
  gray700: '#374151',
  gray900: '#111827',
};

const M = 30;
const ROW_HEIGHT = 25;

function fmtDate(dateStr?: string | Date): string {
  if (!dateStr) return '';
  const d = new Date(dateStr);
  if (isNaN(d.getTime())) return '';
  return `${String(d.getDate()).padStart(2, '0')}/${String(d.getMonth() + 1).padStart(2, '0')}/${d.getFullYear()}`;
}

@Injectable()
export class JobsPdfService {
  async generateJobRegisterPdf(jobs: any[]): Promise<Buffer> {
    const ROWS_PER_PAGE = 15;
    const chunks = this.chunkArray(jobs, ROWS_PER_PAGE);
    const totalPages = chunks.length || 1;

    const doc = new PDFDocument({
      layout: 'landscape',
      size: 'A4',
      margins: { top: M, bottom: M, left: M, right: M },
      autoFirstPage: false, // we add pages manually
    });

    const buffers: Buffer[] = [];
    doc.on('data', (c: Buffer) => buffers.push(c));

    return new Promise((resolve, reject) => {
      doc.on('end', () => resolve(Buffer.concat(buffers)));
      doc.on('error', reject);

      // If no jobs, render one empty page
      const pagesToRender = chunks.length > 0 ? chunks : [[]];

      pagesToRender.forEach((pageJobs, pageIdx) => {
        doc.addPage();

        const pageW = doc.page.width; // ~841.89
        const pageH = doc.page.height; // ~595.28
        const cw = pageW - M * 2;

        let y = M;
        y = this.drawHeader(doc, y, cw, M, pageIdx + 1, totalPages);
        this.drawTable(doc, y, cw, M, pageJobs);
        this.drawFooter(doc, pageH - M - 32, cw, M);
      });

      doc.end();
    });
  }

  // ═══════════════════════════════════════════════
  //  HEADER
  // ═══════════════════════════════════════════════
  private drawHeader(
    doc: any,
    y: number,
    cw: number,
    lm: number,
    page: number,
    total: number,
  ): number {
    const row1H = 66;
    const row2H = 28;

    const col1W = cw * 0.2;
    const col2W = cw * 0.6;
    const col3W = cw * 0.2;

    // ── Row 1 border ───────────────────────────────
    doc.lineWidth(1);
    doc.rect(lm, y, cw, row1H).stroke(B.black);
    doc
      .moveTo(lm + col1W, y)
      .lineTo(lm + col1W, y + row1H)
      .stroke(B.black);
    doc
      .moveTo(lm + col1W + col2W, y)
      .lineTo(lm + col1W + col2W, y + row1H)
      .stroke(B.black);

    // Logo
    const logoPath = path.join(process.cwd(), 'assets', 'logo.png');
    if (fs.existsSync(logoPath)) {
      try {
        doc.image(logoPath, lm + 6, y + 6, {
          fit: [col1W - 12, row1H - 12],
          align: 'center',
          valign: 'center',
        });
      } catch {
        this.drawLogoFallback(doc, lm, y, col1W, row1H);
      }
    } else {
      this.drawLogoFallback(doc, lm, y, col1W, row1H);
    }

    // Company name — two lines
    const titleX = lm + col1W;
    const titleW = col2W;
    doc
      .font('Helvetica-Bold')
      .fontSize(18)
      .fillColor(B.black)
      .text('QUALITY REGISTRAR', titleX, y + 14, {
        width: titleW,
        align: 'center',
        lineBreak: false,
      });
    doc
      .font('Helvetica-Bold')
      .fontSize(18)
      .fillColor(B.black)
      .text('SYSTEMS', titleX, y + 38, {
        width: titleW,
        align: 'center',
        lineBreak: false,
      });

    // Page number
    doc
      .font('Helvetica')
      .fontSize(9)
      .fillColor(B.gray700)
      .text(
        `Page ${page} of ${total}`,
        lm + col1W + col2W + 4,
        y + row1H / 2 - 6,
        { width: col3W - 8, align: 'right', lineBreak: false },
      );

    // ── Row 2 ──────────────────────────────────────
    const row2Y = y + row1H;
    doc.lineWidth(1);
    doc.rect(lm, row2Y, cw, row2H).stroke(B.black);

    doc
      .font('Helvetica-Bold')
      .fontSize(14)
      .fillColor(B.black)
      .text('Job Register', lm, row2Y + 7, {
        width: cw,
        align: 'center',
        lineBreak: false,
      });

    doc
      .font('Helvetica')
      .fontSize(8)
      .fillColor(B.gray500)
      .text('Form 02-2', lm + cw - 62, row2Y + row2H - 14, {
        width: 58,
        align: 'right',
        lineBreak: false,
      });

    return row2Y + row2H + 4;
  }

  private drawLogoFallback(
    doc: any,
    lm: number,
    y: number,
    col1W: number,
    row1H: number,
  ) {
    const fx = lm + col1W / 2 - 20;
    const fy = y + row1H / 2 - 12;
    doc.rect(fx, fy, 40, 24).fillAndStroke('#E5E7EB', B.black);
    doc
      .font('Helvetica-Bold')
      .fontSize(10)
      .fillColor(B.gray700)
      .text('QRS', fx, fy + 7, {
        width: 40,
        align: 'center',
        lineBreak: false,
      });
  }

  // ═══════════════════════════════════════════════
  //  TABLE
  // ═══════════════════════════════════════════════
  private readonly COLUMNS = [
    { label: 'Job No', w: 140, align: 'left' },
    { label: 'Company Name', w: 165, align: 'left' },
    { label: 'Doc Review', w: 68, align: 'center' },
    { label: 'On Site Audit', w: 68, align: 'center' },
    { label: 'Auditor', w: 108, align: 'left' },
    { label: 'Employees', w: 55, align: 'center' },
    { label: 'NACE/EAC', w: 62, align: 'center' },
    { label: 'M/D', w: 46, align: 'center' },
    { label: 'RISK', w: 50, align: 'center' },
  ];

  private drawTable(
    doc: any,
    startY: number,
    cw: number,
    lm: number,
    jobs: any[],
  ) {
    const rawTotal = this.COLUMNS.reduce((s, c) => s + c.w, 0);
    const scale = cw / rawTotal;
    const cols = this.COLUMNS.map((c) => ({ ...c, pw: c.w * scale }));

    let y = startY;
    const thH = 22;

    // ── Table header row ────────────────────────────
    // Fill first, then re-draw rect for border
    doc.rect(lm, y, cw, thH).fill(B.gray900);
    doc.lineWidth(1);
    doc.rect(lm, y, cw, thH).stroke(B.black);

    let x = lm;
    cols.forEach((col, ci) => {
      doc
        .font('Helvetica-Bold')
        .fontSize(8)
        .fillColor(B.white)
        .text(col.label, x + 3, y + 7, {
          width: col.pw - 6,
          align: col.align as any,
          lineBreak: false,
        });
      x += col.pw;
      // Column dividers
      if (ci < cols.length - 1) {
        doc
          .moveTo(x, y)
          .lineTo(x, y + thH)
          .strokeColor(B.gray500)
          .lineWidth(0.5)
          .stroke();
      }
    });

    y += thH;

    // ── Data rows ───────────────────────────────────
    jobs.forEach((job, idx) => {
      const isAlt = idx % 2 === 1;

      // Background fill
      if (isAlt) {
        doc.rect(lm, y, cw, ROW_HEIGHT).fill(B.gray50);
      }

      // Bottom border line
      doc
        .moveTo(lm, y + ROW_HEIGHT)
        .lineTo(lm + cw, y + ROW_HEIGHT)
        .strokeColor(B.gray200)
        .lineWidth(0.4)
        .stroke();

      // Cell text
      const cells = this.extractCells(job);
      let cx = lm;

      cols.forEach((col, ci) => {
        const val = cells[ci] ?? 'N/A';

        doc
          .font('Helvetica')
          .fontSize(7.5)
          .fillColor(B.gray900)
          .text(String(val), cx + 3, y + 6, {
            width: col.pw - 6,
            align: col.align as any,
            lineBreak: ci === 0, // ← only Job No wraps
            ellipsis: ci !== 0, // ← ellipsis for all others
          });

        cx += col.pw;

        // Column divider
        if (ci < cols.length - 1) {
          doc
            .moveTo(cx, y)
            .lineTo(cx, y + ROW_HEIGHT)
            .strokeColor(B.gray200)
            .lineWidth(0.3)
            .stroke();
        }
      });

      y += ROW_HEIGHT;
    });

    // Outer border over whole table (header + rows)
    doc.lineWidth(1);
    doc.rect(lm, startY, cw, y - startY).stroke(B.black);
  }

  private extractCells(job: any): string[] {
    return [
      (job.jobCodes || []).join(', ') || 'N/A',
      job.company?.name || 'N/A',
      fmtDate(job.docReview),
      fmtDate(job.date),
      job.leadAuditor
        ? `${job.leadAuditor.firstName} ${job.leadAuditor.lastName}`
        : 'N/A',
      String(job.numEmployees ?? 'N/A'),
      job.naceEacCodes || 'N/A',
      job.md || 'N/A',
      job.mdRisk || 'N/A',
    ];
  }

  // ═══════════════════════════════════════════════
  //  FOOTER
  // ═══════════════════════════════════════════════
  private drawFooter(doc: any, y: number, cw: number, lm: number) {
    const footerH = 28;
    const colW = cw / 3;

    doc.lineWidth(1);
    doc.rect(lm, y, cw, footerH).stroke(B.black);
    doc
      .moveTo(lm + colW, y)
      .lineTo(lm + colW, y + footerH)
      .stroke(B.black);
    doc
      .moveTo(lm + colW * 2, y)
      .lineTo(lm + colW * 2, y + footerH)
      .stroke(B.black);

    const items = [
      { label: 'Issue', value: '01' },
      { label: 'Revision', value: '00' },
      { label: 'Date', value: '20.02.2011' },
    ];

    items.forEach((item, i) => {
      const cx = lm + colW * i;
      doc
        .font('Helvetica')
        .fontSize(8)
        .fillColor(B.gray700)
        .text(item.label, cx, y + 5, {
          width: colW,
          align: 'center',
          lineBreak: false,
        });
      doc
        .font('Helvetica-Bold')
        .fontSize(9)
        .fillColor(B.black)
        .text(item.value, cx, y + 15, {
          width: colW,
          align: 'center',
          lineBreak: false,
        });
    });
  }

  // ═══════════════════════════════════════════════
  //  UTILS
  // ═══════════════════════════════════════════════
  private chunkArray<T>(arr: T[], size: number): T[][] {
    const chunks: T[][] = [];
    for (let i = 0; i < arr.length; i += size) {
      chunks.push(arr.slice(i, i + size));
    }
    return chunks;
  }
}
