<?php
// ============================================================
// CertificateController
// ============================================================
requireRole(['admin', 'lab_officer']);

require_once __DIR__ . '/../helpers/ILabForm.php';
require_once __DIR__ . '/../helpers/ILabCertificate.php';
require_once __DIR__ . '/../helpers/LabRegistry.php';
require_once __DIR__ . '/../helpers/GenericLabCertificate.php';

$db     = Database::getInstance();
$action = $_GET['action'] ?? 'index';
$uid    = (int)$_SESSION['user_id'];

// ── Ensure output directories exist ─────────────────────────
foreach ([CERT_PATH, SIGNATURE_PATH] as $dir) {
    if (!is_dir($dir)) {
        mkdir($dir, 0755, true);
    }
}

// ── Helper: load full request row ───────────────────────────
function loadFullRequest(PDO $db, int $rid): ?array {
    $stmt = $db->prepare("
        SELECT r.*,
               c.company_name, c.address AS co_address,
               c.phone AS co_phone, c.email AS co_email,
               e.equipment_name, e.model, e.serial_number,
               e.manufacturer, e.range_capacity,
               l.lab_id, l.lab_name, l.lab_code, l.department
        FROM requests r
        JOIN companies   c  ON r.company_id   = c.company_id
        JOIN equipment   e  ON r.equipment_id = e.equipment_id
        JOIN laboratories l ON r.lab_id       = l.lab_id
        WHERE r.request_id = ?
    ");
    $stmt->execute([$rid]);
    return $stmt->fetch() ?: null;
}

// ── Helper: safe filename slug from cert number ──────────────
function certSlug(string $certNum): string {
    return preg_replace('/[^A-Za-z0-9_\-]/', '-', $certNum);
}

switch ($action) {

    // ─────────────────────────────────────────────────────────
    case 'index':
        $stmt = $db->prepare("
            SELECT cert.*, r.request_number,
                   c.company_name, e.equipment_name,
                   l.lab_name, u.officer_name AS issued_by_name
            FROM certificates cert
            JOIN requests    r  ON cert.request_id = r.request_id
            JOIN companies   c  ON r.company_id    = c.company_id
            JOIN equipment   e  ON r.equipment_id  = e.equipment_id
            JOIN laboratories l ON r.lab_id        = l.lab_id
            JOIN users        u ON cert.issued_by  = u.user_id
            ORDER BY cert.date_created DESC
        ");
        $stmt->execute();
        $certificates = $stmt->fetchAll();
        include __DIR__ . '/../views/lab/certificates_index.php';
        break;

    // ─────────────────────────────────────────────────────────
    case 'generate':
        $rid     = (int)($_GET['request_id'] ?? 0);
        $request = loadFullRequest($db, $rid);

        if (!$request) {
            setFlash('error', 'Request not found.');
            header('Location: ' . APP_URL . '/index.php?page=requests');
            exit;
        }
        if (!userCanAccessLab($uid, $request['lab_id'])) {
            setFlash('error', 'Access denied.');
            header('Location: ' . APP_URL . '/index.php?page=requests');
            exit;
        }

        $labCode     = strtoupper($request['lab_code']);
        $formHandler = LabRegistry::getFormHandler($labCode);
        $formData    = $formHandler->load($rid);

        if (!$formData || !$formHandler->isSubmitted($formData)) {
            setFlash('error', 'Work form must be submitted before generating a certificate.');
            header('Location: ' . APP_URL . '/index.php?page=workform&action=edit&request_id=' . $rid);
            exit;
        }

        // Check for existing certificate
        $stmt = $db->prepare('SELECT * FROM certificates WHERE request_id = ?');
        $stmt->execute([$rid]);
        $existing = $stmt->fetch();
        if ($existing) {
            setFlash('info', 'Certificate already generated.');
            header('Location: ' . APP_URL . '/index.php?page=certificates&action=view&id=' . $existing['cert_id']);
            exit;
        }

        // Officer info
        $stmt = $db->prepare('SELECT * FROM users WHERE user_id = ?');
        $stmt->execute([$uid]);
        $officer = $stmt->fetch();

        $certNum   = generateCertNumber($request['lab_code']);
        $issueDate = date('Y-m-d');
        $slug      = certSlug($certNum);

        $certHandler = LabRegistry::getCertificateHandler($labCode);

        // ── Generate HTML file ───────────────────────────────
        $htmlFilename = 'CERT_' . $slug . '.html';
        $htmlPath     = CERT_PATH . $htmlFilename;
        $htmlContent  = $certHandler->generateHTML($request, $formData, $officer, $certNum, $issueDate);

        $htmlWritten = file_put_contents($htmlPath, $htmlContent);
        if ($htmlWritten === false) {
            setFlash('error', 'Certificate directory is not writable. Please create the directory: '
                . CERT_PATH . ' and ensure it is writable by the web server.');
            header('Location: ' . APP_URL . '/index.php?page=requests&action=view&id=' . $rid);
            exit;
        }

        // ── Try wkhtmltopdf → fall back to HTML ──────────────
        $pdfFilename = 'CERT_' . $slug . '.pdf';
        $pdfPath     = CERT_PATH . $pdfFilename;
        $wk          = trim((string)shell_exec('which wkhtmltopdf 2>/dev/null'));
        $savedPdfName = $htmlFilename; // default fallback

        if ($wk) {
            $wkCmd = escapeshellcmd($wk)
                . ' --quiet --page-size A4'
                . ' --margin-top 15mm --margin-bottom 15mm'
                . ' --margin-left 18mm --margin-right 18mm'
                . ' ' . escapeshellarg($htmlPath)
                . ' ' . escapeshellarg($pdfPath)
                . ' 2>&1';
            shell_exec($wkCmd);
            if (file_exists($pdfPath) && filesize($pdfPath) > 1024) {
                $savedPdfName = $pdfFilename;
            }
        }

        // ── Generate XML file ─────────────────────────────────
        $xmlFilename = 'DCC_' . $slug . '.xml';
        $xmlPath     = CERT_PATH . $xmlFilename;
        $xmlContent  = $certHandler->generateXML($request, $formData, $officer, $certNum, $issueDate);
        $xmlWritten  = file_put_contents($xmlPath, $xmlContent);

        if ($xmlWritten === false) {
            error_log("MetLAB: Failed to write XML certificate to $xmlPath");
            $xmlFilename = ''; // store empty if write failed
        }

        // ── Save to DB ────────────────────────────────────────
        try {
            $db->prepare('INSERT INTO certificates
                (cert_number, request_id, form_id, issued_by, pdf_path, xml_path, issue_date)
                VALUES (?, ?, ?, ?, ?, ?, ?)')
               ->execute([
                   $certNum,
                   $rid,
                   $formData['form_id'] ?? null,
                   $uid,
                   $savedPdfName,
                   $xmlFilename,
                   $issueDate,
               ]);
            $certId = (int)$db->lastInsertId();
        } catch (PDOException $e) {
            error_log('MetLAB: Certificate DB insert failed: ' . $e->getMessage());
            setFlash('error', 'Certificate files generated but database save failed: ' . $e->getMessage());
            header('Location: ' . APP_URL . '/index.php?page=requests&action=view&id=' . $rid);
            exit;
        }

        $db->prepare("UPDATE requests SET status='completed' WHERE request_id=?")->execute([$rid]);
        logActivity('generate_certificate', 'certificates', "Certificate $certNum generated for {$labCode}", $certId);
        setFlash('success', "Certificate $certNum generated successfully.");
        header('Location: ' . APP_URL . '/index.php?page=certificates&action=view&id=' . $certId);
        exit;

    // ─────────────────────────────────────────────────────────
    case 'view':
        $certId = (int)($_GET['id'] ?? 0);
        $stmt   = $db->prepare("
            SELECT cert.*, r.request_number, r.request_date, r.request_id,
                   u.officer_name AS issued_by_name, u.signature,
                   l.lab_name, l.lab_code
            FROM certificates cert
            JOIN requests    r ON cert.request_id = r.request_id
            JOIN laboratories l ON r.lab_id       = l.lab_id
            JOIN users        u ON cert.issued_by  = u.user_id
            WHERE cert.cert_id = ?
        ");
        $stmt->execute([$certId]);
        $cert = $stmt->fetch();
        if (!$cert) {
            setFlash('error', 'Certificate not found.');
            header('Location: ' . APP_URL . '/index.php?page=certificates');
            exit;
        }

        $request     = loadFullRequest($db, $cert['request_id']);
        $labCode     = strtoupper($cert['lab_code']);
        $formHandler = LabRegistry::getFormHandler($labCode);
        $formData    = $formHandler->load($cert['request_id']);
        $officer     = ['officer_name' => $cert['issued_by_name'], 'signature' => $cert['signature']];

        $certView = LabRegistry::getCertView($labCode);
        include __DIR__ . '/../views/' . $certView;
        break;

    // ─────────────────────────────────────────────────────────
    case 'download':
        $certId = (int)($_GET['id'] ?? 0);
        $type   = in_array($_GET['type'] ?? '', ['pdf','xml']) ? $_GET['type'] : 'pdf';

        $stmt = $db->prepare('SELECT * FROM certificates WHERE cert_id = ?');
        $stmt->execute([$certId]);
        $cert = $stmt->fetch();

        if (!$cert) {
            http_response_code(404);
            die('Certificate record not found.');
        }

        $filename = ($type === 'xml') ? $cert['xml_path'] : $cert['pdf_path'];

        if (empty($filename)) {
            http_response_code(404);
            die('No ' . strtoupper($type) . ' file was generated for this certificate.');
        }

        $file = CERT_PATH . $filename;

        // Debug info — remove after confirming downloads work
        if (!file_exists($file)) {
            http_response_code(404);
            $msg  = 'File not found on server.' . PHP_EOL;
            $msg .= 'Expected path: ' . $file . PHP_EOL;
            $msg .= 'CERT_PATH = ' . CERT_PATH . PHP_EOL;
            $msg .= 'Directory exists: ' . (is_dir(CERT_PATH) ? 'YES' : 'NO') . PHP_EOL;
            $msg .= 'Files in directory: ' . PHP_EOL;
            if (is_dir(CERT_PATH)) {
                foreach (scandir(CERT_PATH) as $f) {
                    $msg .= '  ' . $f . PHP_EOL;
                }
            }
            die($msg);
        }

        $ext  = strtolower(pathinfo($file, PATHINFO_EXTENSION));
        $mime = match ($ext) {
            'pdf'  => 'application/pdf',
            'xml'  => 'application/xml',
            'html' => 'text/html',
            default => 'application/octet-stream',
        };

        // Clear any buffered output to avoid corrupting binary files
        if (ob_get_level()) ob_end_clean();

        header('Content-Type: ' . $mime);
        header('Content-Disposition: attachment; filename="' . basename($file) . '"');
        header('Content-Length: ' . filesize($file));
        header('Cache-Control: no-cache, must-revalidate');
        header('Pragma: no-cache');
        readfile($file);
        exit;
}

// ── Generic cert generators (fallback for non-specific labs) ──

function generateCertHTML(string $certNum, array $req, array $form, array $officer, array $measData, array $refEquip, string $issueDate): string {
    $e = fn($v) => htmlspecialchars((string)($v ?? ''), ENT_QUOTES, 'UTF-8');
    $rows = '';
    foreach ($measData['rows'] ?? [] as $i => $row) {
        $rows .= '<tr><td>' . ($i+1) . '</td><td>' . $e($row['name'] ?? '') . '</td>'
               . '<td>' . $e($row['nominal'] ?? '') . '</td><td>' . $e($row['measured'] ?? '') . '</td>'
               . '<td>' . $e($row['error'] ?? '') . '</td><td>' . $e($row['uncertainty'] ?? '') . '</td>'
               . '<td>' . $e($row['unit'] ?? '') . '</td></tr>';
    }
    $refHtml = '';
    foreach ($refEquip as $ref) {
        $refHtml .= '<tr><td>' . $e($ref['name'] ?? '') . '</td>'
                  . '<td>' . $e($ref['serial'] ?? '') . '</td>'
                  . '<td>' . $e($ref['cert'] ?? '') . '</td></tr>';
    }
    $sigImg = '';
    if (!empty($officer['signature']) && file_exists(SIGNATURE_PATH . $officer['signature'])) {
        $sigData = base64_encode(file_get_contents(SIGNATURE_PATH . $officer['signature']));
        $sigImg  = '<img src="data:image/png;base64,' . $sigData . '" style="max-height:60px;">';
    }
    return '<!DOCTYPE html><html><head><meta charset="UTF-8">
<title>Certificate ' . $e($certNum) . '</title>
<style>body{font-family:Arial,sans-serif;font-size:10pt;}table{width:100%;border-collapse:collapse;}th,td{border:1px solid #ccc;padding:4px 6px;}thead th{background:#003366;color:#fff;}.nb td,.nb th{border:none;}h2{color:#003366;}@media print{.no-print{display:none}}</style>
</head><body>
<h2>Ghana Standards Authority — Calibration Certificate</h2>
<p><strong>Certificate No.:</strong> ' . $e($certNum) . ' &nbsp;&nbsp; <strong>Date:</strong> ' . $e($issueDate) . '</p><hr>
<table class="nb">
  <tr><td><strong>Company:</strong> ' . $e($req['company_name']) . '</td><td><strong>Equipment:</strong> ' . $e($req['equipment_name']) . '</td></tr>
  <tr><td><strong>Manufacturer:</strong> ' . $e($req['manufacturer'] ?? '') . '</td><td><strong>Model:</strong> ' . $e($req['model'] ?? '') . '</td></tr>
  <tr><td><strong>Serial No.:</strong> ' . $e($req['serial_number'] ?? '') . '</td><td><strong>Lab:</strong> ' . $e($req['lab_name']) . '</td></tr>
</table><hr>
' . (!empty($refHtml) ? '<h4>Reference Standards</h4><table><thead><tr><th>Equipment</th><th>Serial No.</th><th>Certificate No.</th></tr></thead><tbody>' . $refHtml . '</tbody></table><hr>' : '') . '
<h4>Measurement Results</h4>
<table><thead><tr><th>#</th><th>Point</th><th>Nominal</th><th>Measured</th><th>Error</th><th>Uncertainty</th><th>Unit</th></tr></thead>
<tbody>' . ($rows ?: '<tr><td colspan="7" style="text-align:center;color:#888;">No measurement data.</td></tr>') . '</tbody></table><hr>
<p><strong>Uncertainty:</strong> ' . $e($form['uncertainty_statement'] ?? '') . ' k=' . $e($form['coverage_factor'] ?? '2') . '</p>
<div style="margin-top:30px;text-align:right;">' . $sigImg . '<br><strong>' . $e($officer['officer_name'] ?? '') . '</strong></div>
</body></html>';
}

function generateDCCXml(string $certNum, array $req, array $form, array $officer, array $measData, string $issueDate): string {
    $e    = fn($v) => htmlspecialchars(trim((string)$v), ENT_XML1, 'UTF-8');
    $rows = '';
    foreach ($measData['rows'] ?? [] as $i => $row) {
        $n = $i + 1;
        $rows .= '<dcc:result refType="gp_result' . $n . '"><dcc:name><dcc:content lang="en">' . $e($row['name'] ?? "Result $n") . '</dcc:content></dcc:name>'
               . '<dcc:data><dcc:quantity refType="basic_measuredValue"><si:real>'
               . '<si:value>' . $e($row['measured'] ?? '0') . '</si:value>'
               . '<si:unit>' . $e($row['unit'] ?? '') . '</si:unit></si:real>'
               . '</dcc:quantity></dcc:data></dcc:result>';
    }
    return '<?xml version="1.0" encoding="UTF-8"?>'
         . '<dcc:digitalCalibrationCertificate xmlns:dcc="https://ptb.de/dcc" xmlns:si="https://ptb.de/si" schemaVersion="3.2.1">'
         . '<dcc:administrativeData><dcc:coreData>'
         . '<dcc:uniqueIdentifier>' . $e($certNum) . '</dcc:uniqueIdentifier>'
         . '<dcc:endPerformanceDate>' . $e($issueDate) . '</dcc:endPerformanceDate>'
         . '</dcc:coreData><dcc:items><dcc:item>'
         . '<dcc:name><dcc:content lang="en">' . $e($req['equipment_name']) . '</dcc:content></dcc:name>'
         . '</dcc:item></dcc:items>'
         . '<dcc:respPersons><dcc:respPerson><dcc:person><dcc:name>' . $e($officer['officer_name'] ?? '') . '</dcc:name></dcc:person></dcc:respPerson></dcc:respPersons>'
         . '</dcc:administrativeData>'
         . '<dcc:measurementResults><dcc:measurementResult><dcc:results>' . $rows . '</dcc:results></dcc:measurementResult></dcc:measurementResults>'
         . '</dcc:digitalCalibrationCertificate>';
}
