<?php
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
 * GPL v3+
 *
 * Visueller Editor fuer die Unterschriftsbox auf Lieferschein-PDFs.
 * Laedt ein Beispiel-Lieferschein-PDF (PDF.js), zeigt die aktuelle Box als
 * Fabric.js-Rechteck und speichert die mm-Geometrie in llx_bericht_signature_box.
 */

$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { $i--; $j--; }
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php";
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
if (!$res) die("Include of main fails");

require_once __DIR__.'/../lib/bericht.lib.php';
require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';

if (!$user->admin && !$user->hasRight('bericht', 'admin')) accessforbidden();
$langs->loadLangs(array("admin", "bericht@bericht"));

// Verfuegbare Templates: PDF-Module + ODT-Module + ODT-Dateien aus doctemplates/shipments/
$tpl_dir = DOL_DOCUMENT_ROOT.'/core/modules/expedition/doc';
$pdf_modules = array();  // ['espadon' => 'espadon', ...]
$odt_modules = array();  // ['generic_shipment_odt' => 'generic_shipment_odt']
if (is_dir($tpl_dir)) {
    foreach (glob($tpl_dir.'/pdf_*.modules.php') as $f) {
        $name = basename($f);
        if (preg_match('/^pdf_(.+)\.modules\.php$/', $name, $m)) {
            $pdf_modules[$m[1]] = $m[1];
        }
    }
    foreach (glob($tpl_dir.'/doc_*.modules.php') as $f) {
        $name = basename($f);
        if (preg_match('/^doc_(.+)\.modules\.php$/', $name, $m)) {
            $odt_modules[$m[1]] = $m[1];
        }
    }
}

// ODT-Dateien aus doctemplates/shipments/ — pro Datei eine eigene Box konfigurierbar
// EXPEDITION_ADDON_PDF_ODT_PATH enthaelt 'DOL_DATA_ROOT' woertlich + ist komma/zeilengetrennt
$odt_files = array();
$raw_dirs = getDolGlobalString('EXPEDITION_ADDON_PDF_ODT_PATH', 'DOL_DATA_ROOT/doctemplates/shipments');
foreach (explode(',', preg_replace('/[\r\n]+/', ',', trim($raw_dirs))) as $d) {
    $d = trim($d);
    if (!$d) continue;
    $d = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $d);
    if (!is_dir($d)) continue;
    foreach (glob($d.'/*.odt') as $f) {
        $name = basename($f);
        $key = 'odt:'.preg_replace('/\.odt$/i', '', $name);
        $odt_files[$key] = $name;
    }
}

$active_template = getDolGlobalString('EXPEDITION_ADDON_PDF', 'merou');
$selected = GETPOST('template', 'alphanohtml') ?: $active_template;

// Wenn nichts uebergeben + es gibt ODTs + Aktives Modul ist generic_shipment_odt → erstes ODT vorauswaehlen
if (!GETPOST('template', 'alphanohtml') && $active_template === 'generic_shipment_odt' && !empty($odt_files)) {
    $selected = array_key_first($odt_files);
}

// Auswahl validieren
$all_choices = array_merge($pdf_modules, $odt_modules, $odt_files);
if (!isset($all_choices[$selected])) {
    $selected = $active_template;
    if (!isset($all_choices[$selected]) && !empty($all_choices)) {
        $selected = array_key_first($all_choices);
    }
}

// Aktuelle Box-Geometrie fuer das ausgewaehlte Template laden (oder Default)
$box = bericht_get_signature_box($db, $selected);

// Letzte vorhandene Expedition fuer Preview suchen — sonst Hinweis ausgeben
$preview_shipment_id = 0;
$r = $db->query("SELECT rowid FROM ".$db->prefix()."expedition"
    ." WHERE entity IN (".getEntity('expedition').")"
    ." ORDER BY rowid DESC LIMIT 1");
if ($r && ($o = $db->fetch_object($r))) $preview_shipment_id = (int) $o->rowid;

llxHeader('', $langs->trans("BerichtSignatureBoxConfig"));

$linkback = '<a href="'.dol_buildpath('/bericht/admin/setup.php', 1).'">'.$langs->trans("BackToSetup").'</a>';
print load_fiche_titre($langs->trans("BerichtSignatureBoxConfig"), $linkback, 'title_setup');
print '<p class="opacitymedium">'.$langs->trans("BerichtSignatureBoxConfigDesc").'</p>';

// Template-Wahl mit Gruppen
print '<form method="get" style="margin-bottom:16px;">';
print '<label style="margin-right:8px;">'.$langs->trans("BerichtPdfTemplate").':</label>';
print '<select name="template" onchange="this.form.submit()">';
if (!empty($odt_files)) {
    print '<optgroup label="'.dol_escape_htmltag($langs->trans("BerichtOdtFiles")).'">';
    foreach ($odt_files as $key => $filename) {
        $sel = ($key === $selected) ? ' selected' : '';
        $hint = ($active_template === 'generic_shipment_odt') ? ' ★' : '';
        print '<option value="'.dol_escape_htmltag($key).'"'.$sel.'>'.dol_escape_htmltag($filename).$hint.'</option>';
    }
    print '</optgroup>';
}
if (!empty($pdf_modules)) {
    print '<optgroup label="'.dol_escape_htmltag($langs->trans("BerichtPdfModules")).'">';
    foreach ($pdf_modules as $tpl) {
        $sel = ($tpl === $selected) ? ' selected' : '';
        $is_active = ($tpl === $active_template) ? ' ★' : '';
        print '<option value="'.dol_escape_htmltag($tpl).'"'.$sel.'>'.dol_escape_htmltag($tpl).$is_active.'</option>';
    }
    print '</optgroup>';
}
if (!empty($odt_modules)) {
    print '<optgroup label="'.dol_escape_htmltag($langs->trans("BerichtOdtModules")).'">';
    foreach ($odt_modules as $tpl) {
        $sel = ($tpl === $selected) ? ' selected' : '';
        $is_active = ($tpl === $active_template) ? ' ★' : '';
        print '<option value="'.dol_escape_htmltag($tpl).'"'.$sel.'>'.dol_escape_htmltag($tpl).$is_active.'</option>';
    }
    print '</optgroup>';
}
print '</select>';
print ' <span class="opacitymedium" style="font-size:12px;">★ = aktuell in Dolibarr aktiv</span>';
print '</form>';

// Hinweis bei ODT-Auswahl: mm-Editor ist hier NICHT relevant.
// Stattdessen: Bild-Platzhalter "signature" im ODT einbauen — die Position waechst dann automatisch mit dem PDF-Inhalt mit.
$is_odt = (strpos($selected, 'odt:') === 0);
if ($is_odt) {
    $sig_ratio = getDolGlobalString('BERICHT_SIGNATURE_IMAGE_RATIO', '0.35');
    print '<div class="info" style="background:#1e3a5f;border:1px solid #4080c0;color:#e0e8f0;padding:14px 18px;border-radius:8px;margin-bottom:16px;font-size:14px;line-height:1.6;">';
    print '<h4 style="margin:0 0 8px;color:#fff;">📄 ODT-Template — Platzhalter-Methode (wie EPCQR/{qrcode})</h4>';
    print '<p style="margin:0;">Bei ODT-Vorlagen ist die mm-Box <strong>nicht sinnvoll</strong>: das PDF wird je nach Positionsmenge unterschiedlich lang — fixe Position würde mitten in den Zeilen landen.</p>';
    print '<p style="margin:10px 0 4px;font-weight:600;">Stattdessen:</p>';
    print '<ol style="margin:4px 0 0 18px;padding:0;">';
    print '<li>In deinem ODT (<code>'.dol_escape_htmltag($odt_files[$selected] ?? '').'</code>) an die gewünschte Stelle den Text-Platzhalter <code>{signature}</code> schreiben — irgendwo, wo die Unterschrift erscheinen soll.</li>';
    print '<li>Drumherum optional Text-Variablen einsetzen: <code>{signer_name}</code>, <code>{signed_at}</code>, <code>{gps}</code>, <code>{kunde_name}</code>, <code>{kunde_adresse}</code>, <code>{shipment_ref}</code>, <code>{order_ref}</code>, <code>{auftragsnummer}</code>, <code>{datum}</code>.</li>';
    print '<li>Speichern. Fertig.</li>';
    print '</ol>';
    print '<p style="margin:12px 0 4px;font-size:12px;opacity:0.85;">Beim Bestätigen in der PWA ersetzt <code>setImage()</code> den <code>{signature}</code>-Text durch ein <code>&lt;draw:frame&gt;</code> mit der Kunden-Unterschrift. Die Größe wird durch den Faktor <code>BERICHT_SIGNATURE_IMAGE_RATIO</code> (aktuell <strong>'.dol_escape_htmltag($sig_ratio).'</strong>) gesteuert — bei 0.35 ergibt das ca. 7×3.5 cm.</p>';
    print '<p style="margin:8px 0 0;font-size:12px;opacity:0.6;">Die mm-Felder rechts sind hier ohne Wirkung — sie gelten nur für reine PDF-Module (espadon/merou/rouget).</p>';
    print '</div>';
}

if (!$preview_shipment_id) {
    print '<div class="warning">'.$langs->trans("BerichtSignatureBoxNoPreviewShipment").'</div>';
} else {
    // PDF-URL fuer die Vorschau: nutzt den shipments.php-Endpoint mit JWT
    // Hier brauchen wir keinen JWT, weil wir admin sind und das PDF lokal lesen.
    // Stattdessen: Vorschau-Endpoint nimmt nur die Expedition-ID und laedt das PDF.
    $preview_url = dol_buildpath('/bericht/admin/signature_box_preview.php', 1)
        .'?id='.$preview_shipment_id
        .'&template='.urlencode($selected);

    print '<div class="bericht-setup-section">';
    print '<div style="display:flex;gap:24px;flex-wrap:wrap;align-items:flex-start;">';

    // Linke Spalte: PDF-Vorschau mit Box
    print '<div style="flex:1;min-width:400px;">';
    print '<h4>'.$langs->trans("BerichtPreviewWithBox").'</h4>';
    print '<style>'
        .'#pdf-container { position:relative; display:inline-block; line-height:0; }'
        // PDF zeichnen-Canvas: bleibt im Fluss
        .'#pdf-container > canvas:first-child { display:block; position:relative; z-index:1; }'
        // Fabric wraps in .canvas-container — der muss absolut OBEN drauf liegen
        .'#pdf-container .canvas-container { position:absolute !important; top:0 !important; left:0 !important; z-index:10 !important; }'
        // Innere Canvas (upper + lower) auch sauber stacked
        .'#pdf-container .canvas-container canvas { position:absolute; top:0; left:0; }'
        .'</style>';
    print '<div id="pdf-stage" style="background:#222;padding:8px;border-radius:6px;display:inline-block;max-width:100%;overflow:auto;">';
    print '<div id="pdf-container"></div>';
    print '</div>';
    print '<div style="margin-top:8px;display:flex;gap:8px;align-items:center;">';
    print '<button type="button" id="btn-prev-page" class="butAction">‹</button>';
    print '<span id="page-info">…</span>';
    print '<button type="button" id="btn-next-page" class="butAction">›</button>';
    print '</div>';
    print '</div>';

    // Rechte Spalte: Werte editierbar + Speichern (bei ODT optisch gedimmt)
    $right_attr = $is_odt ? ' style="flex:0 0 280px;opacity:0.5;pointer-events:none;"' : ' style="flex:0 0 280px;"';
    print '<div'.$right_attr.'>';
    print '<h4>'.$langs->trans("BerichtBoxGeometry").($is_odt ? ' <span style="font-size:11px;font-weight:normal;">(bei ODT inaktiv)</span>' : '').'</h4>';
    print '<form id="box-form">';
    print '<input type="hidden" name="template_name" value="'.dol_escape_htmltag($selected).'">';
    print '<table class="noborder centpercent">';
    print '<tr><td>'.$langs->trans("BerichtBoxPage").'</td><td><select name="page">';
    foreach (array('last' => $langs->trans("BerichtBoxPageLast"), 'first' => $langs->trans("BerichtBoxPageFirst")) as $v => $l) {
        $sel = ($box['page'] == $v) ? ' selected' : '';
        print '<option value="'.$v.'"'.$sel.'>'.$l.'</option>';
    }
    print '</select></td></tr>';
    print '<tr><td>X (mm)</td><td><input type="number" step="0.5" name="x_mm" id="inp-x" value="'.((float) $box['x_mm']).'"></td></tr>';
    print '<tr><td>Y (mm)</td><td><input type="number" step="0.5" name="y_mm" id="inp-y" value="'.((float) $box['y_mm']).'"></td></tr>';
    print '<tr><td>'.$langs->trans("Width").' (mm)</td><td><input type="number" step="0.5" name="w_mm" id="inp-w" value="'.((float) $box['w_mm']).'"></td></tr>';
    print '<tr><td>'.$langs->trans("Height").' (mm)</td><td><input type="number" step="0.5" name="h_mm" id="inp-h" value="'.((float) $box['h_mm']).'"></td></tr>';
    print '<tr><td>'.$langs->trans("BerichtBoxLabel").'</td><td><input type="text" name="label" value="'.dol_escape_htmltag($box['label']).'"></td></tr>';
    print '</table>';
    print '<br>';
    print '<button type="button" id="btn-save-box" class="butAction">💾 '.$langs->trans("Save").'</button>';
    print '<button type="button" id="btn-reset-box" class="butAction" style="margin-left:8px;">'.$langs->trans("BerichtBoxResetDefault").'</button>';
    print '<div id="save-status" style="margin-top:8px;opacity:0.7;font-size:13px;"></div>';
    print '</form>';
    print '</div>'; // rechte Spalte
    print '</div>'; // Flex
    print '</div>'; // section

    // PDF.js einbinden + Editor-JS
    $pdfjs_url = dol_buildpath('/bericht/js/lib/pdf.min.js', 1);
    $pdfjs_worker_url = dol_buildpath('/bericht/js/lib/pdf.worker.min.js', 1);
    $fabric_url = dol_buildpath('/bericht/js/lib/fabric.min.js', 1);
    $save_url = dol_buildpath('/bericht/ajax/save_signature_box.php', 1);
    ?>
    <script src="<?php echo dol_escape_htmltag($pdfjs_url); ?>"></script>
    <script src="<?php echo dol_escape_htmltag($fabric_url); ?>"></script>
    <script>
    (function () {
        if (window.pdfjsLib) {
            window.pdfjsLib.GlobalWorkerOptions.workerSrc = <?php echo json_encode($pdfjs_worker_url); ?>;
        }
        const PDF_URL = <?php echo json_encode($preview_url); ?>;
        const SAVE_URL = <?php echo json_encode($save_url); ?>;
        const TEMPLATE = <?php echo json_encode($selected); ?>;
        const IS_ODT  = <?php echo json_encode($is_odt); ?>;
        const DEFAULT_BOX = <?php echo json_encode(bericht_get_signature_box($db, '')); ?>;
        // 1 PDF-Point = 25.4/72 mm
        const PT_TO_MM = 25.4 / 72.0;

        let pdfDoc = null, pageNum = 1, pageCount = 0;
        let pageWmm = 210, pageHmm = 297;
        let renderScale = 1.0;
        let fabricCanvas = null, fabricRect = null;

        const stage = document.getElementById('pdf-container');
        const inpX = document.getElementById('inp-x');
        const inpY = document.getElementById('inp-y');
        const inpW = document.getElementById('inp-w');
        const inpH = document.getElementById('inp-h');
        const pageInfo = document.getElementById('page-info');

        function chosenPageNum() {
            const pageSel = document.querySelector('select[name="page"]').value;
            if (pageSel === 'first') return 1;
            return pageCount; // last
        }

        async function loadPdf() {
            const buf = await fetch(PDF_URL, { credentials: 'same-origin' }).then(r => r.arrayBuffer());
            pdfDoc = await pdfjsLib.getDocument({ data: buf }).promise;
            pageCount = pdfDoc.numPages;
            pageNum = chosenPageNum();
            await renderPage();
        }

        async function renderPage() {
            const page = await pdfDoc.getPage(pageNum);
            const viewport1 = page.getViewport({ scale: 1 });
            // PDF-Punkte → mm
            pageWmm = viewport1.width * PT_TO_MM;
            pageHmm = viewport1.height * PT_TO_MM;

            // Skala so waehlen, dass max 700px breit
            const targetW = Math.min(700, window.innerWidth - 360);
            renderScale = targetW / viewport1.width;
            const viewport = page.getViewport({ scale: renderScale });

            // Stage clear + Canvas zeichnen
            stage.innerHTML = '';
            const canvas = document.createElement('canvas');
            canvas.width = viewport.width;
            canvas.height = viewport.height;
            canvas.style.display = 'block';
            stage.appendChild(canvas);

            const ctx = canvas.getContext('2d');
            await page.render({ canvasContext: ctx, viewport: viewport }).promise;

            // Fabric-Layer obendrueber
            const fabricEl = document.createElement('canvas');
            fabricEl.width = viewport.width;
            fabricEl.height = viewport.height;
            fabricEl.style.position = 'absolute';
            fabricEl.style.top = '0';
            fabricEl.style.left = '0';
            stage.appendChild(fabricEl);

            if (fabricCanvas) { try { fabricCanvas.dispose(); } catch (e) {} }
            fabricCanvas = new fabric.Canvas(fabricEl, { selection: false });
            // Container-Geometrie auf PDF-Canvas-Groesse fixieren, damit das Fabric-Overlay
            // (vom CSS '#pdf-container .canvas-container' absolut positioniert) deckt.
            stage.style.height = viewport.height + 'px';
            stage.style.width = viewport.width + 'px';
            const fabricWrap = stage.querySelector('.canvas-container');
            if (fabricWrap) {
                fabricWrap.style.width = viewport.width + 'px';
                fabricWrap.style.height = viewport.height + 'px';
            }

            // Box aus aktuellen Werten
            drawBoxFromInputs();

            pageInfo.textContent = 'Seite ' + pageNum + ' / ' + pageCount + '  (' + pageWmm.toFixed(0) + ' × ' + pageHmm.toFixed(0) + ' mm)';
        }

        function drawBoxFromInputs() {
            if (!fabricCanvas) return;
            // ODT: keine Box zeichnen — Position kommt aus dem ODT-Bildplatzhalter
            if (IS_ODT) {
                fabricCanvas.clear();
                fabricRect = null;
                return;
            }
            // Wenn Seite nicht der Box-Seite entspricht: keine Box zeigen
            if (pageNum !== chosenPageNum()) {
                fabricCanvas.clear();
                fabricRect = null;
                return;
            }
            const xmm = parseFloat(inpX.value) || 0;
            const ymm = parseFloat(inpY.value) || 0;
            const wmm = parseFloat(inpW.value) || 50;
            const hmm = parseFloat(inpH.value) || 25;

            // mm → px = mm / PT_TO_MM * renderScale
            const mm2px = (mm) => (mm / PT_TO_MM) * renderScale;

            fabricCanvas.clear();
            fabricRect = new fabric.Rect({
                left: mm2px(xmm),
                top:  mm2px(ymm),
                width:  mm2px(wmm),
                height: mm2px(hmm),
                fill: 'rgba(60,140,220,0.20)',
                stroke: '#1e6fc0',
                strokeWidth: 2,
                cornerColor: '#1e6fc0',
                transparentCorners: false,
                hasRotatingPoint: false,
                lockRotation: true,
            });
            fabricCanvas.add(fabricRect);
            fabricCanvas.setActiveObject(fabricRect);

            fabricRect.on('modified', syncInputsFromRect);
            fabricRect.on('moving',   syncInputsFromRect);
            fabricRect.on('scaling',  syncInputsFromRect);
        }

        function syncInputsFromRect() {
            if (!fabricRect) return;
            const px2mm = (px) => (px / renderScale) * PT_TO_MM;
            const wPx = fabricRect.width * (fabricRect.scaleX || 1);
            const hPx = fabricRect.height * (fabricRect.scaleY || 1);
            inpX.value = px2mm(fabricRect.left).toFixed(1);
            inpY.value = px2mm(fabricRect.top).toFixed(1);
            inpW.value = px2mm(wPx).toFixed(1);
            inpH.value = px2mm(hPx).toFixed(1);
        }

        // Bei Number-Input-Aenderung Box neu zeichnen
        [inpX, inpY, inpW, inpH].forEach(el => el.addEventListener('input', drawBoxFromInputs));
        document.querySelector('select[name="page"]').addEventListener('change', () => {
            pageNum = chosenPageNum();
            renderPage();
        });

        document.getElementById('btn-prev-page').onclick = () => { if (pageNum > 1) { pageNum--; renderPage(); } };
        document.getElementById('btn-next-page').onclick = () => { if (pageNum < pageCount) { pageNum++; renderPage(); } };

        document.getElementById('btn-reset-box').onclick = () => {
            inpX.value = DEFAULT_BOX.x_mm;
            inpY.value = DEFAULT_BOX.y_mm;
            inpW.value = DEFAULT_BOX.w_mm;
            inpH.value = DEFAULT_BOX.h_mm;
            document.querySelector('input[name="label"]').value = DEFAULT_BOX.label || 'Unterschrift Kunde';
            document.querySelector('select[name="page"]').value = DEFAULT_BOX.page || 'last';
            pageNum = chosenPageNum();
            renderPage();
        };

        document.getElementById('btn-save-box').onclick = async () => {
            const status = document.getElementById('save-status');
            status.textContent = 'Speichere…';
            const fd = new FormData(document.getElementById('box-form'));
            fd.append('token', <?php echo json_encode(newToken()); ?>);
            try {
                const r = await fetch(SAVE_URL, { method: 'POST', body: fd, credentials: 'same-origin' });
                const j = await r.json();
                if (j.ok) status.textContent = '✓ Gespeichert um ' + new Date().toLocaleTimeString();
                else status.textContent = '✕ ' + (j.error || 'Fehler');
            } catch (e) {
                status.textContent = '✕ ' + e.message;
            }
        };

        loadPdf();
    })();
    </script>
    <?php
}

llxFooter();
$db->close();
