<?php
declare(strict_types=1);

namespace App\Shared\Services;

use App\Core\Response;

final class PdfExportService
{
    public static function renderToHtml(string $viewPath, array $data, string $filename): Response
    {
        $modulePath = str_replace('.', '/', $viewPath);
        $filePath = __DIR__ . '/../../Modules/' . $modulePath . '.php';

        if (!file_exists($filePath)) {
            $response = new Response();
            return $response->html('<h1>Template not found</h1>', 404);
        }

        extract($data, EXTR_SKIP);
        ob_start();
        include $filePath;
        $html = ob_get_clean();

        $response = new Response();
        return $response->html($html, 200, [
            'Content-Type' => 'text/html; charset=utf-8',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
        ]);
    }

    public static function renderToPdf(string $html, string $filename): Response
    {
        $wkhtmltopdf = self::findBinary();

        if ($wkhtmltopdf) {
            $tmpInput = tempnam(sys_get_temp_dir(), 'pdf_in_') . '.html';
            $tmpOutput = tempnam(sys_get_temp_dir(), 'pdf_out_') . '.pdf';

            file_put_contents($tmpInput, $html);

            $cmd = escapeshellarg($wkhtmltopdf)
                . ' --encoding utf-8'
                . ' --page-size A4'
                . ' --margin-top 15 --margin-bottom 15 --margin-left 12 --margin-right 12'
                . ' --enable-local-file-access'
                . ' --no-stop-slow-scripts'
                . ' --javascript-delay 500'
                . ' --image-quality 85'
                . ' --print-media-type'
                . ' ' . escapeshellarg($tmpInput)
                . ' ' . escapeshellarg($tmpOutput)
                . ' 2>&1';

            exec($cmd, $output, $returnCode);

            @unlink($tmpInput);

            if (($returnCode === 0 || $returnCode === 1) && file_exists($tmpOutput) && filesize($tmpOutput) > 0) {
                $pdfContent = file_get_contents($tmpOutput);
                @unlink($tmpOutput);

                $response = new Response();
                return $response->html($pdfContent, 200, [
                    'Content-Type' => 'application/pdf',
                    'Content-Disposition' => 'attachment; filename="' . $filename . '"',
                    'Content-Length' => (string) strlen($pdfContent),
                ]);
            }
            @unlink($tmpOutput);
        }

        $response = new Response();
        return $response->html($html, 200, [
            'Content-Type' => 'text/html; charset=utf-8',
            'Content-Disposition' => 'attachment; filename="' . str_replace('.pdf', '.html', $filename) . '"',
        ]);
    }

    private static function findBinary(): ?string
    {
        $paths = [
            '/usr/local/bin/wkhtmltopdf',
            '/usr/bin/wkhtmltopdf',
            '/snap/bin/wkhtmltopdf',
        ];

        foreach ($paths as $path) {
            if (file_exists($path) && is_executable($path)) {
                return $path;
            }
        }

        $which = trim((string) shell_exec('which wkhtmltopdf 2>/dev/null'));
        if (!empty($which) && is_executable($which)) {
            return $which;
        }

        return null;
    }
}
