import { Injectable } from '@nestjs/common';
import PDFDocument from 'pdfkit';
import { ReportData, CertRow } from './report.service';

// Brand palette (QRS purple), matching the email.
const C = {
  purple: '#8B14D4', purpleDark: '#4A0080', light: '#F8F5FF', border: '#EDE8FF',
  white: '#FFFFFF', gray50: '#F8F9FB', gray200: '#E5E7EB', gray500: '#6B7280',
  gray700: '#374151', dark: '#1A0440',
  coral: '#D85A30', teal: '#1D9E75', amber: '#BA7517',
};
const M = 40;
const COMPANY = 'QUALITY REGISTRAR SYSTEMS';

function fmtDate(d?: string | null): string {
  if (!d) return '—';
  const dt = new Date(d);
  if (isNaN(dt.getTime())) return String(d);
  return dt.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' });
}

interface FlatRow extends CertRow {
  category: string;
  accent: string;
}

@Injectable()
export class ReportPdfService {
  async generate(report: ReportData, summary: string): Promise<Buffer> {
    const doc = new PDFDocument({
      layout: 'landscape', size: 'A4',
      margins: { top: M, bottom: 50, left: M, right: M },
      bufferPages: true, info: { Title: 'Certification Report', Author: 'QRS' },
    });
    const buffers: Buffer[] = [];
    doc.on('data', (c: Buffer) => buffers.push(c));

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

      const accents: Record<string, string> = { recert: C.coral, surv_11: C.teal, surv_1: C.amber };
      const rows: FlatRow[] = report.buckets.flatMap((b) =>
        b.rows.map((r) => ({ ...r, category: b.label, accent: accents[b.key] ?? C.purple })),
      );

      this.header(doc, `${report.monthName} ${report.year}`);
      this.summary(doc, summary);
      this.cards(doc, report);
      this.table(doc, rows);
      this.footers(doc);
      doc.end();
    });
  }

  private header(doc: any, monthLabel: string) {
    const pw = doc.page.width, cw = pw - M * 2;
    doc.rect(0, 0, pw, 64).fill(C.purpleDark);
    doc.rect(0, 0, pw, 64).fillOpacity(0.0).fill();
    doc.fillOpacity(1);
    doc.font('Helvetica').fontSize(9).fillColor(C.white).text(COMPANY, M, 14, { width: cw / 2, characterSpacing: 1 });
    doc.font('Helvetica-Bold').fontSize(17).fillColor(C.white).text('Certification Report', M, 28, { width: cw / 2 });
    doc.font('Helvetica').fontSize(10).fillColor(C.white)
      .text(monthLabel, pw / 2, 22, { width: cw / 2, align: 'right' });
    doc.font('Helvetica').fontSize(8).fillColor(C.white)
      .text(`Generated: ${fmtDate(new Date().toISOString())}`, pw / 2, 38, { width: cw / 2, align: 'right' });
    doc.rect(0, 64, pw, 3).fill(C.purple);
    doc.fillColor(C.dark); doc.y = 80;
  }

  private summary(doc: any, summary: string) {
    const cw = doc.page.width - M * 2;
    doc.font('Helvetica').fontSize(9.5).fillColor(C.gray700)
      .text(summary, M, doc.y, { width: cw, lineGap: 2 });
    doc.y += 8;
  }

  private cards(doc: any, report: ReportData) {
    const cw = doc.page.width - M * 2;
    const gap = 10;
    const items = [
      { label: 'TOTAL DUE', value: report.total, accent: C.purple },
      ...report.buckets.map((b) => ({
        label: b.label.toUpperCase(),
        value: b.count,
        accent: ({ recert: C.coral, surv_11: C.teal, surv_1: C.amber } as any)[b.key] ?? C.purple,
      })),
    ];
    const cardW = (cw - gap * (items.length - 1)) / items.length;
    const sy = doc.y, cardH = 46;
    items.forEach((it, i) => {
      const x = M + i * (cardW + gap);
      doc.roundedRect(x, sy, cardW, cardH, 6).fill(C.gray50);
      doc.rect(x, sy, cardW, 3).fill(it.accent);
      doc.font('Helvetica-Bold').fontSize(7).fillColor(C.gray500).text(it.label, x + 12, sy + 9, { width: cardW - 24 });
      doc.font('Helvetica-Bold').fontSize(20).fillColor(it.accent).text(String(it.value), x + 12, sy + 18, { width: cardW - 24 });
    });
    doc.fillColor(C.dark); doc.y = sy + cardH + 16;
  }

  private table(doc: any, rows: FlatRow[]) {
    const headers = [
      { label: 'CERT NO', width: 120, align: 'left' },
      { label: 'COMPANY', width: 210, align: 'left' },
      { label: 'STANDARD', width: 90, align: 'left' },
      { label: 'ORIG. REG', width: 70, align: 'center' },
      { label: 'EXPIRE', width: 70, align: 'center' },
      { label: 'STATUS', width: 55, align: 'center' },
      { label: 'CATEGORY', width: 95, align: 'center' },
    ];
    const cw = doc.page.width - M * 2;
    const totalW = headers.reduce((s, h) => s + h.width, 0);
    const scale = cw / totalW;
    const headerH = 22;
    let y = doc.y;

    const drawHead = (atY: number) => {
      doc.rect(M, atY, cw, headerH).fill(C.purple);
      let x = M;
      headers.forEach((h) => {
        const colW = h.width * scale;
        doc.font('Helvetica-Bold').fontSize(7.5).fillColor(C.white)
          .text(h.label, x + 5, atY + 7, { width: colW - 10, align: h.align as any });
        x += colW;
      });
      return atY + headerH;
    };
    y = drawHead(y);

    rows.forEach((r, idx) => {
      doc.font('Helvetica').fontSize(8);
      const nameH = doc.heightOfString(r.company_name ?? '—', { width: headers[1].width * scale - 10 });
      const rowH = Math.max(18, nameH + 8);
      if (y + rowH > doc.page.height - 60) { doc.addPage(); y = drawHead(M); }
      if (idx % 2 === 1) doc.rect(M, y, cw, rowH).fill(C.gray50);
      doc.moveTo(M, y + rowH).lineTo(M + cw, y + rowH).strokeColor(C.gray200).lineWidth(0.3).stroke();

      const cells = [
        { v: r.cert_no ?? '—', color: C.dark, bold: true, align: 'left' },
        { v: r.company_name ?? '—', color: C.dark, bold: false, align: 'left' },
        { v: r.standard ?? '—', color: C.gray700, bold: false, align: 'left' },
        { v: fmtDate(r.orginally_reg), color: C.gray700, bold: false, align: 'center' },
        { v: fmtDate(r.expire_date), color: C.gray700, bold: false, align: 'center' },
        { v: r.status ?? '—', color: C.gray700, bold: false, align: 'center' },
        { v: r.category, color: r.accent, bold: true, align: 'center' },
      ];
      let x = M;
      cells.forEach((cell, ci) => {
        const colW = headers[ci].width * scale;
        doc.font(cell.bold ? 'Helvetica-Bold' : 'Helvetica').fontSize(8).fillColor(cell.color)
          .text(String(cell.v), x + 5, y + 5, { width: colW - 10, align: cell.align as any });
        x += colW;
      });
      y += rowH;
    });

    doc.moveTo(M, y).lineTo(M + cw, y).strokeColor(C.purple).lineWidth(1.5).stroke();
    doc.rect(M, y, cw, 22).fill(C.light);
    doc.font('Helvetica-Bold').fontSize(9).fillColor(C.purpleDark)
      .text(`TOTAL: ${rows.length} certificates`, M + 5, y + 6, { width: cw - 10, align: 'left' });
    doc.y = y + 34; doc.fillColor(C.dark);
  }

  private footers(doc: any) {
    const pages = doc.bufferedPageRange();
    for (let i = 0; i < pages.count; i++) {
      doc.switchToPage(i);
      const pH = doc.page.height, pW = doc.page.width, c3 = (pW - M * 2) / 3;
      doc.moveTo(M, pH - 35).lineTo(pW - M, pH - 35).strokeColor(C.gray200).lineWidth(0.5).stroke();
      doc.font('Helvetica').fontSize(7).fillColor(C.gray500);
      doc.text(COMPANY, M, pH - 28, { width: c3, align: 'left' });
      doc.text(`Page ${i + 1} of ${pages.count}`, M + c3, pH - 28, { width: c3, align: 'center' });
      doc.text(`Printed: ${fmtDate(new Date().toISOString())}`, M + c3 * 2, pH - 28, { width: c3, align: 'right' });
    }
  }
}