const PDFDocument = require('pdfkit');
const QRCode = require('qrcode');
const bwipjs = require('bwip-js');

const MM = 2.8346; // points per mm
const A4_W = 595.28;
const A4_H = 841.89;
const PAGE_MARGIN = 15 * MM;
const LABEL_GAP = 4 * MM;

// Label sizes in mm. ptouch:true = each label gets its own PDF page at exact tape size
const LABEL_SIZES = {
    small:     { w: 50,  h: 25, ptouch: false },
    medium:    { w: 62,  h: 29, ptouch: false },
    large:     { w: 90,  h: 38, ptouch: false },
    ptouch12:  { w: 71.1, h: 12, ptouch: true  },
};

/**
 * Generate a PDF with asset labels.
 * @param {object} asset  - Asset object from DB
 * @param {number} copies - Number of labels to generate
 * @param {string} size   - 'small' | 'medium' | 'large' | 'ptouch12'
 * @returns {Promise<Buffer>} PDF as buffer
 */
async function generateAssetLabel(asset, copies = 1, size = 'medium') {
    const labelMm = LABEL_SIZES[size] || LABEL_SIZES.medium;

    if (labelMm.ptouch) {
        return _generatePtouchPdf(asset, copies, labelMm);
    }

    const FRONTEND_URL = process.env.FRONTEND_URL || 'http://localhost:3000';
    const qrData = asset.serial_number
        ? `${FRONTEND_URL}/defect?serial=${encodeURIComponent(asset.serial_number)}`
        : asset.name;
    const qrBuffer = await QRCode.toBuffer(qrData, {
        width: 600,
        margin: 0,
        color: { dark: '#000000', light: '#ffffff' },
    });
    return _generateA4Pdf(asset, qrBuffer, copies, labelMm);
}

// ── A4 layout (multiple labels per page) ─────────────────────────────────────

async function _generateA4Pdf(asset, qrBuffer, copies, labelMm) {
    const lw = labelMm.w * MM;
    const lh = labelMm.h * MM;

    const usableW = A4_W - 2 * PAGE_MARGIN;
    const usableH = A4_H - 2 * PAGE_MARGIN;
    const cols = Math.max(1, Math.floor((usableW + LABEL_GAP) / (lw + LABEL_GAP)));
    const rows = Math.max(1, Math.floor((usableH + LABEL_GAP) / (lh + LABEL_GAP)));
    const perPage = cols * rows;

    const doc = new PDFDocument({ size: 'A4', margin: 0, autoFirstPage: true });
    const buffers = [];
    doc.on('data', (chunk) => buffers.push(chunk));

    for (let i = 0; i < copies; i++) {
        if (i > 0 && i % perPage === 0) {
            doc.addPage({ size: 'A4', margin: 0 });
        }
        const posOnPage = i % perPage;
        const col = posOnPage % cols;
        const row = Math.floor(posOnPage / cols);
        const x = PAGE_MARGIN + col * (lw + LABEL_GAP);
        const y = PAGE_MARGIN + row * (lh + LABEL_GAP);
        _drawLabel(doc, asset, qrBuffer, x, y, lw, lh);
    }

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

// ── P-Touch layout (one label per page at exact tape size) ───────────────────

async function _generatePtouchPdf(asset, copies, labelMm) {
    const lw = labelMm.w * MM;
    const lh = labelMm.h * MM;
    const pageSize = [lw, lh];

    // Barcode als SVG → wird als Vektoren in PDF gerendert (pixelscharf bei jedem DPI)
    const barcodeText = asset.serial_number || asset.name || 'UNKNOWN';
    const barcodeSvg = bwipjs.toSVG({
        bcid:        'code128',
        text:        barcodeText,
        scale:       1,
        height:      10,
        includetext: false,
        paddingwidth: 0,
        paddingheight: 0,
    });

    const doc = new PDFDocument({ size: pageSize, margin: 0, autoFirstPage: true });
    const buffers = [];
    doc.on('data', (chunk) => buffers.push(chunk));

    for (let i = 0; i < copies; i++) {
        if (i > 0) doc.addPage({ size: pageSize, margin: 0 });
        _drawPtouchLabel(doc, asset, barcodeSvg, lw, lh);
    }

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

/**
 * Zeichnet Code-128-SVG als native PDFKit-Vektoren (kein Rasterisieren → druckt pixel-scharf).
 */
function _drawBarcodeVectors(doc, svgStr, bx, by, bw, bh) {
    const vbMatch = svgStr.match(/viewBox="0 0 ([\d.]+) ([\d.]+)"/);
    if (!vbMatch) return;
    const svgW = parseFloat(vbMatch[1]);
    const svgH = parseFloat(vbMatch[2]);
    const sx = bw / svgW;
    const sy = bh / svgH;

    doc.save().fillColor('#000000');
    const pathRe = /stroke-width="([\d.]+)"[^>]+d="([^"]+)"|d="([^"]+)"[^>]+stroke-width="([\d.]+)"/g;
    // Simpler: two separate regexes
    const paths = [...svgStr.matchAll(/<path[^>]+stroke-width="([\d.]+)"[^>]+d="([^"]+)"/g)];
    for (const pm of paths) {
        const sw = parseFloat(pm[1]) * sx;
        const segs = [...pm[2].matchAll(/M([\d.]+) /g)];
        for (const sm of segs) {
            const cx = parseFloat(sm[1]) * sx;
            doc.rect(bx + cx - sw / 2, by, sw, bh).fill();
        }
    }
    doc.restore();
}

/**
 * Draw a 12mm P-Touch label — P-Touch style: left text block + right barcode.
 * Layout:
 *   ┌──────────────┬───────────────────────────────┐
 *   │ Asset Name   │  |||||||||||||||||||||||||    │
 *   │ MM.YYYY      │  SN / Inventarnummer          │
 *   └──────────────┴───────────────────────────────┘
 */
function _drawPtouchLabel(doc, asset, barcodeSvg, w, h) {
    const mL = 2 * MM;
    const mR = 2 * MM;
    const mT = 1.2 * MM;
    const mB = 1.2 * MM;

    const inner_w = w - mL - mR;
    const inner_h = h - mT - mB;

    // Split: left text block ~32%, right barcode ~68%
    const textColW = inner_w * 0.32;
    const barcodeColW = inner_w - textColW - 0.5 * MM; // 0.5mm divider gap
    const barcodeX = mL + textColW + 0.5 * MM;

    // ── Outer border
    doc.save()
        .rect(mL, mT, inner_w, inner_h)
        .strokeColor('#000000').lineWidth(0.4).stroke()
        .restore();

    // ── Horizontal divider (splits text block in two rows)
    const midY = mT + inner_h / 2;
    doc.save()
        .moveTo(mL, midY).lineTo(mL + textColW, midY)
        .strokeColor('#000000').lineWidth(0.3).stroke()
        .restore();

    // ── Vertical divider
    doc.save()
        .moveTo(mL + textColW, mT).lineTo(mL + textColW, mT + inner_h)
        .strokeColor('#000000').lineWidth(0.3).stroke()
        .restore();

    // ── Top cell: asset name
    const nameSize = 4.5;
    const topCellH = inner_h / 2;
    const nameY = mT + (topCellH - nameSize) / 2;
    doc.fontSize(nameSize)
        .fillColor('#000000')
        .font('Helvetica-Bold')
        .text(asset.name || '-', mL + 1 * MM, nameY, {
            width: textColW - 2 * MM,
            lineBreak: false,
            ellipsis: true,
        });

    // ── Bottom cell: date (MM.YYYY from purchase_date or created_at)
    const dateSize = 4;
    const rawDate = asset.purchase_date || asset.created_at;
    let dateStr = '-';
    if (rawDate) {
        const d = new Date(rawDate);
        if (!isNaN(d)) {
            const mm = String(d.getMonth() + 1).padStart(2, '0');
            const yyyy = d.getFullYear();
            dateStr = `${mm}.${yyyy}`;
        }
    }
    const dateY = midY + (topCellH - dateSize) / 2;
    doc.fontSize(dateSize)
        .fillColor('#000000')
        .font('Helvetica')
        .text(dateStr, mL + 1 * MM, dateY, {
            width: textColW - 2 * MM,
            lineBreak: false,
        });

    // ── Barcode als Vektoren (keine PNG-Rasterisierung)
    const snFontSize = 5;
    const snH = snFontSize + 0.8 * MM;
    const barcodeAvailH = inner_h - snH - 0.2 * MM;
    const barcodeImgW = barcodeColW - mR * 0.5;

    _drawBarcodeVectors(doc, barcodeSvg, barcodeX, mT, barcodeImgW, barcodeAvailH);

    // Seriennummer als Vektor-Text
    const snText = asset.serial_number || asset.name || '';
    const snY = mT + barcodeAvailH + 0.3 * MM;
    doc.fontSize(snFontSize)
        .fillColor('#000000')
        .font('Helvetica-Bold')
        .text(snText, barcodeX, snY, {
            width: barcodeImgW,
            align: 'center',
            lineBreak: false,
            ellipsis: true,
        });
}

// ── Standard A4 label draw ────────────────────────────────────────────────────

function _drawLabel(doc, asset, qrBuffer, x, y, w, h) {
    const pad = 3 * MM;
    const qrSize = h - 2 * pad;
    const textX = x + qrSize + pad * 1.5;
    const textW = w - qrSize - pad * 2.5;

    // Label border
    doc.save()
        .rect(x, y, w, h)
        .strokeColor('#d1d5db')
        .lineWidth(0.5)
        .stroke()
        .restore();

    // QR code
    doc.image(qrBuffer, x + pad, y + pad, { width: qrSize, height: qrSize });

    // Vertical divider
    doc.save()
        .moveTo(x + qrSize + pad, y + pad)
        .lineTo(x + qrSize + pad, y + h - pad)
        .strokeColor('#e5e7eb')
        .lineWidth(0.3)
        .stroke()
        .restore();

    // "IT Nexus" branding
    const brandY = y + pad;
    doc.fontSize(5)
        .fillColor('#0d9488')
        .font('Helvetica-Bold')
        .text('IT Nexus', textX, brandY, { width: textW, lineBreak: false });

    // Asset name
    const nameY = brandY + 7;
    const nameFontSize = h > 30 * MM ? 8 : 7;
    doc.fontSize(nameFontSize)
        .fillColor('#111827')
        .font('Helvetica-Bold')
        .text(asset.name, textX, nameY, { width: textW, lineBreak: false, ellipsis: true });

    // Type
    if (asset.type && h > 22 * MM) {
        const typeY = nameY + nameFontSize + 1;
        doc.fontSize(5.5)
            .fillColor('#6b7280')
            .font('Helvetica')
            .text(asset.type, textX, typeY, { width: textW, lineBreak: false });
    }

    // Serial number (bottom area)
    const snFontSize = 6.5;
    const snY = y + h - pad - snFontSize;
    doc.fontSize(snFontSize)
        .fillColor('#111827')
        .font('Helvetica-Bold')
        .text(asset.serial_number || '-', textX, snY, { width: textW, lineBreak: false, ellipsis: true });

    // Model (very small, if space)
    if (asset.model && h > 30 * MM) {
        doc.fontSize(4.5)
            .fillColor('#9ca3af')
            .font('Helvetica')
            .text(asset.model, textX, snY - 6, { width: textW, lineBreak: false, ellipsis: true });
    }
}

module.exports = { generateAssetLabel, LABEL_SIZES };
