import jsPDF from 'jspdf';
import dejavuFont from '@/fonts/DejaVuSans-normal.js';

const directorsSingLabel = 'Генеральный директор ООО "ИТБ" ______________________________ Иванов Д. А.';

// Кол-во воркеров для выгрузки изображений - чтобы не срать сразу 1000 запросами на s3
const promiseWorkers = 4;

/**
 * Загружает картинку по URL и конвертирует в dataURL,
 * Если не удалось — до трёх попыток с бэкоффом, потом null.
 */
async function loadImageAsDataUrl(url, { widthPx, heightPx } = {}) {
    const maxAttempts = 3;
    const baseDelay = 200; // ms

    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
        try {
            const res = await fetch(url, { mode: 'cors' });
            if (!res.ok) throw new Error(`HTTP ${res.status}`);
            const blob = await res.blob();
            let dataUrl = await new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload  = () => resolve(reader.result);
                reader.onerror = reject;
                reader.readAsDataURL(blob);
            });

            // если нужно ресайзить
            if (widthPx && heightPx) {
                const img = await new Promise((res, rej) => {
                    const i = new Image();
                    i.crossOrigin = 'Anonymous';
                    i.onload  = () => res(i);
                    i.onerror = rej;
                    i.src     = dataUrl;
                });
                const canvas = document.createElement('canvas');
                canvas.width  = widthPx;
                canvas.height = heightPx;
                const ctx = canvas.getContext('2d');
                ctx.drawImage(img, 0, 0, widthPx, heightPx);
                dataUrl = canvas.toDataURL('image/jpeg');
            }

            return dataUrl;
        } catch (e) {
            if (attempt < maxAttempts) {
                console.warn(
                    `Попытка ${attempt} не удалась для ${url}:`,
                    e.message,
                    `— повтор через ${baseDelay * attempt}ms`
                );
                await new Promise(r => setTimeout(r, baseDelay * attempt));
            } else {
                console.error(`Все ${maxAttempts} попыток не удались для ${url}:`, e);
                return null;
            }
        }
    }
}

/**
 * Собирает PDF из массива photo-объектов:
 *   { url, day, timeStart, number, name, lat, lng }
 * и сохраняет его под указанным именем.
 */
export async function generatePhotosPdf(photos, {
    title = '',
    subtitle = '',
    signatureData,
    stampData,
    fileName
} = {}) {
    const doc = new jsPDF({ unit: 'mm', format: 'a4' });
    const dpi = 150;
    const pageW = doc.internal.pageSize.getWidth();
    const pageH = doc.internal.pageSize.getHeight();
    const margin = 10;
    const perPage = 15;
    const cellW = (pageW - margin*2) / 3;
    const cellH = (pageH - margin*2 - 10) / 5;
    const pxPerMm = dpi / 25.4;

    // подключаем шрифт
    doc.addFileToVFS('DejaVuSans.ttf', dejavuFont);
    doc.addFont('DejaVuSans.ttf', 'DejaVuSans', 'normal');
    doc.setFont('DejaVuSans');
    doc.setFontSize(10);

    // подготавливаем размеры канваса
    const pw = Math.round(cellW * pxPerMm);
    const ph = Math.round(cellH * pxPerMm);

    // загружаем dataURL’ы с ограничением параллелизма
    const concurrency = promiseWorkers;
    const results = new Array(photos.length);
    let idxPtr = 0;
    async function worker() {
        while (idxPtr < photos.length) {
            const idx = idxPtr++;
            const item = photos[idx];
            if (!item) {
                results[idx] = null;
            } else {
                results[idx] = await loadImageAsDataUrl(item.url, { widthPx: pw, heightPx: ph });
            }
        }
    }
    await Promise.all(Array.from({ length: concurrency }, () => worker()));

    const totalPages = Math.ceil(photos.length / perPage);
    // добиваем до ровных страниц
    const totalSlots = totalPages * perPage;
    while (photos.length < totalSlots) photos.push(null), results.push(null);

    // рисуем по страницам
    for (let page = 0; page < totalPages; page++) {
        if (page > 0) doc.addPage();
        const fullTitle = title + subtitle;
        doc.text(`${fullTitle}`, margin, 10);

        for (let i = 0; i < perPage; i++) {
            const idx = page * perPage + i;
            const item = photos[idx];
            const dataUrl = results[idx];
            const row = Math.floor(i/3), col = i%3;
            const x = margin + col*cellW, y = margin + 6 + row*cellH;
            const pad = 1;

            doc.setDrawColor(200);
            doc.rect(x, y, cellW-pad*2, cellH-pad*2);

            if (item && dataUrl) {
                doc.addImage(dataUrl, 'JPEG', x, y, cellW-pad*2, cellH-pad*2);

                // подпись
                const overlay =
                    `${item.number} ${item.name} · ${item.day} ${item.timeStart} · ${item.lat}, ${item.lng}`;
                doc.setFontSize(6);
                const lines = doc.splitTextToSize(overlay, cellW-pad*2);
                const lh = 1.8;
                const blockH = lines.length*lh + 2 + pad*2;
                const blockY = y - pad + cellH-pad*2 - blockH;

                doc.setFillColor(0);
                doc.setDrawColor(0);
                doc.setGState(new doc.GState({ opacity: 0.5 }));
                doc.rect(x, blockY, cellW-pad*2, blockH, 'F');
                doc.setGState(new doc.GState({ opacity: 1 }));

                doc.setTextColor(255);
                doc.text(lines, x+pad, blockY+1, { baseline: 'top' });
                doc.setTextColor(0);
                doc.setFontSize(10);
            }
        }
    }

    // footer + подпись + печать
    doc.setPage(totalPages);
    doc.setFontSize(10);
    doc.text(
        directorsSingLabel,
        margin,
        pageH - margin + 2
    );

    // подпись и печать
    const sigW = 40, sigH = 20;
    const sigX = (pageW - sigW)/2;
    const sigY = pageH - sigH;
    doc.addImage(signatureData, 'PNG', sigX, sigY, sigW, sigH);

    const stampW = 35, stampH = 35;
    const stampX = sigX + (sigW-stampW)/2 + 15;
    const stampY = sigY + (sigH-stampH)/2 - 10;
    doc.addImage(stampData, 'PNG', stampX, stampY, stampW, stampH);

    // сохраняем
    doc.save(fileName);
}