<?php

namespace App\Http\Controllers;

use App\Transaction;
use App\Utils\BusinessUtil;

class VenoSmartInvoicePreviewController extends Controller
{
    protected $businessUtil;

    public function __construct(BusinessUtil $businessUtil)
    {
        $this->businessUtil = $businessUtil;
    }

    public function show($token)
    {
        $transaction = Transaction::where('invoice_token', $token)
            ->with(['business', 'location', 'contact'])
            ->firstOrFail();

        try {
            return $this->generatePreview($transaction);
        } catch (\Throwable $e) {
            $this->writeErrorLog($e, $token);

            return $this->fallbackResponse($transaction);
        }
    }

    private function generatePreview($transaction)
    {
        if (!function_exists('imagecreatetruecolor')) {
            throw new \RuntimeException(
                'GD extension is not available.'
            );
        }

        $business = $transaction->business;
        $location = $transaction->location;
        $contact = $transaction->contact;

        $businessDetails = $this->businessUtil->getDetails(
            $transaction->business_id
        );

        $businessName = $this->cleanText(
            $business->name ?? 'VENO POS',
            38
        );

        $locationName = $this->cleanText(
            $location->name ?? '',
            42
        );

        $customerName = $this->cleanText(
            $contact->name ?? 'Customer',
            65
        );

        $invoiceNo = $this->cleanText(
            $transaction->invoice_no ?? '',
            20
        );

        $taxNumberRaw = $this->cleanText(
            $business->tax_number_1 ?? '',
            40
        );

        $taxNumber = preg_replace(
            '/^\s*(VAT|TRN|TAX|VAT\s*NO\.?|TRN\s*NO\.?)\s*[:\-]?\s*/i',
            '',
            $taxNumberRaw
        );

        $taxNumber = trim(
            (string) $taxNumber
        );

        $hasTax =
            (float) ($transaction->tax_amount ?? 0) > 0;

        $invoiceTitle = $hasTax
            ? 'TAX INVOICE'
            : 'INVOICE';

        $invoiceTitleAr = $hasTax
            ? 'فاتورة ضريبية'
            : 'فاتورة';

        $invoiceTotalAr = $hasTax
            ? 'إجمالي الفاتورة الضريبية'
            : 'إجمالي الفاتورة';

        $currencySymbol = trim(
            (string) (
                $businessDetails->currency_symbol ?? ''
            )
        );

        $currencyPrecision = (int) (
            $businessDetails->currency_precision ?? 2
        );

        $symbolPlacement =
            $businessDetails->currency_symbol_placement
            ?? 'before';

        $amount = number_format(
            (float) ($transaction->final_total ?? 0),
            $currencyPrecision,
            '.',
            ','
        );

        $formattedTotal = $symbolPlacement === 'after'
            ? trim($amount . ' ' . $currencySymbol)
            : trim($currencySymbol . ' ' . $amount);

        try {
            $invoiceDate = \Carbon\Carbon::parse(
                $transaction->transaction_date
            )->format('d M Y');
        } catch (\Throwable $e) {
            $invoiceDate = '';
        }

        $paymentStatus = strtolower(
            (string) (
                $transaction->payment_status ?? 'due'
            )
        );

        if ($paymentStatus === 'paid') {
            $statusText = 'PAID';
            $statusTextAr = 'مدفوعة';
            $statusHex = '#168A52';
        } elseif (
            $paymentStatus === 'partial' ||
            $paymentStatus === 'partially_paid'
        ) {
            $statusText = 'PARTIALLY PAID';
            $statusTextAr = 'مدفوعة جزئياً';
            $statusHex = '#D97706';
        } elseif ($paymentStatus === 'due') {
            $statusText = 'PAYMENT DUE';
            $statusTextAr = 'مستحقة';
            $statusHex = '#DC2626';
        } else {
            $statusText = 'PENDING';
            $statusTextAr = 'قيد الانتظار';
            $statusHex = '#64748B';
        }

        $width = 1200;
        $height = 630;

        $image = imagecreatetruecolor(
            $width,
            $height
        );

        imagealphablending($image, true);
        imagesavealpha($image, true);

        /*
         * VENO Modern palette.
         */
        $background = $this->allocate(
            $image,
            '#EAF4EF'
        );

        $white = $this->allocate(
            $image,
            '#FFFFFF'
        );

        $green = $this->allocate(
            $image,
            '#168A52'
        );

        $greenDark = $this->allocate(
            $image,
            '#0E6840'
        );

        $greenSoft = $this->allocate(
            $image,
            '#E8F6EF'
        );

        $text = $this->allocate(
            $image,
            '#14231C'
        );

        $muted = $this->allocate(
            $image,
            '#6C7E75'
        );

        $border = $this->allocate(
            $image,
            '#D8E8DF'
        );

        $statusColor = $this->allocate(
            $image,
            $statusHex
        );

        imagefill(
            $image,
            0,
            0,
            $background
        );

        /*
         * Decorative background circles.
         */
        $decorationOne = imagecolorallocatealpha(
            $image,
            22,
            138,
            82,
            105
        );

        $decorationTwo = imagecolorallocatealpha(
            $image,
            14,
            104,
            64,
            112
        );

        imagefilledellipse(
            $image,
            1120,
            30,
            360,
            360,
            $decorationOne
        );

        imagefilledellipse(
            $image,
            45,
            620,
            330,
            330,
            $decorationTwo
        );

        /*
         * Soft card shadow.
         */
        $shadow = imagecolorallocatealpha(
            $image,
            15,
            55,
            36,
            104
        );

        $this->roundedRectangle(
            $image,
            45,
            48,
            1158,
            605,
            34,
            $shadow
        );

        /*
         * Main white card.
         */
        $this->roundedRectangle(
            $image,
            35,
            35,
            1165,
            595,
            34,
            $white
        );

        /*
         * Green header.
         */
        $this->roundedRectangle(
            $image,
            35,
            35,
            1165,
            195,
            34,
            $green
        );

        /*
         * White content area overlaps the lower
         * portion of the header.
         */
        $this->roundedRectangle(
            $image,
            35,
            165,
            1165,
            595,
            30,
            $white
        );

        /*
         * Logo container.
         */
        $logoShadow = imagecolorallocatealpha(
            $image,
            0,
            0,
            0,
            112
        );

        $this->roundedRectangle(
            $image,
            72,
            68,
            172,
            168,
            22,
            $logoShadow
        );

        $this->roundedRectangle(
            $image,
            68,
            64,
            168,
            164,
            22,
            $white
        );

        $logoAdded = $this->addBusinessLogo(
            $image,
            $business,
            80,
            76,
            76,
            76
        );

        if (!$logoAdded) {
            $this->drawText(
                $image,
                'V',
                118,
                134,
                44,
                $green,
                true,
                'center'
            );
        }

        /*
         * Business identity.
         */
        $this->drawFittedMultilineText(
            $image,
            $businessName,
            195,
            101,
            530,
            58,
            31,
            22,
            $white,
            true,
            2
        );

        if ($locationName !== '') {
            $this->drawText(
                $image,
                $locationName,
                195,
                151,
                17,
                $white
            );
        }

        /*
         * Invoice badge.
         */
        $invoiceBadge = $this->allocate(
            $image,
            '#61B987'
        );

        $this->roundedRectangle(
            $image,
            848,
            57,
            1124,
            151,
            18,
            $invoiceBadge
        );

        $this->drawText(
            $image,
            $invoiceTitle,
            986,
            84,
            16,
            $white,
            true,
            'center'
        );

        $this->drawArabicText(
            $image,
            $invoiceTitleAr,
            986,
            112,
            15,
            $white,
            true,
            'center'
        );

        $this->drawText(
            $image,
            '#' . $invoiceNo,
            986,
            140,
            16,
            $white,
            true,
            'center'
        );

        /*
         * Total section.
         */
        $this->drawText(
            $image,
            $invoiceTitle . ' TOTAL',
            78,
            232,
            18,
            $greenDark,
            true
        );

        $this->drawArabicText(
            $image,
            $invoiceTotalAr,
            78,
            263,
            17,
            $greenDark,
            true,
            'left'
        );

        $this->drawText(
            $image,
            $formattedTotal,
            78,
            335,
            53,
            $text,
            true
        );

        if ($hasTax) {
            $this->roundedRectangle(
                $image,
                78,
                354,
                260,
                404,
                18,
                $greenSoft
            );

            $this->drawText(
                $image,
                'VAT INCLUDED',
                169,
                375,
                12,
                $greenDark,
                true,
                'center'
            );

            $this->drawArabicText(
                $image,
                'شامل الضريبة',
                169,
                397,
                12,
                $greenDark,
                true,
                'center'
            );
        }

        if ($hasTax && $taxNumber !== '') {
            $this->drawText(
                $image,
                'TRN / VAT No.: ' . $taxNumber,
                78,
                430,
                14,
                $muted,
                true
            );
        }

        /*
         * Payment status.
         */
        $this->roundedRectangle(
            $image,
            78,
            449,
            345,
            511,
            27,
            $statusColor
        );

        $this->drawText(
            $image,
            $statusText,
            211,
            474,
            16,
            $white,
            true,
            'center'
        );

        $this->drawArabicText(
            $image,
            $statusTextAr,
            211,
            499,
            14,
            $white,
            true,
            'center'
        );

        /*
         * Customer details card.
         */
        $this->roundedRectangle(
            $image,
            600,
            218,
            1112,
            492,
            26,
            $greenSoft
        );

        $this->drawText(
            $image,
            'CUSTOMER',
            642,
            260,
            15,
            $greenDark,
            true
        );

        $this->drawArabicText(
            $image,
            'العميل',
            1068,
            260,
            15,
            $greenDark,
            true,
            'right'
        );

        $this->drawFittedMultilineText(
            $image,
            $customerName,
            642,
            313,
            420,
            76,
            26,
            18,
            $text,
            true,
            2
        );

        /*
         * Divider inside customer card.
         */
        imageline(
            $image,
            642,
            390,
            1068,
            390,
            $border
        );

        $this->drawText(
            $image,
            'INVOICE NO.',
            642,
            416,
            12,
            $muted,
            true
        );

        $this->drawArabicText(
            $image,
            'رقم الفاتورة',
            642,
            438,
            12,
            $muted,
            true,
            'left'
        );

        $this->drawText(
            $image,
            '#' . $invoiceNo,
            642,
            473,
            17,
            $text,
            true
        );

        $this->drawText(
            $image,
            'DATE',
            870,
            416,
            12,
            $muted,
            true
        );

        $this->drawArabicText(
            $image,
            'التاريخ',
            870,
            438,
            12,
            $muted,
            true,
            'left'
        );

        $this->drawText(
            $image,
            $invoiceDate !== ''
                ? $invoiceDate
                : '-',
            870,
            473,
            17,
            $text,
            true
        );

        /*
         * Bottom information strip.
         */
        $this->roundedRectangle(
            $image,
            78,
            521,
            1122,
            564,
            19,
            $greenSoft
        );

        $this->drawText(
            $image,
            'SMART DIGITAL INVOICE',
            100,
            540,
            13,
            $greenDark,
            true
        );

        $this->drawArabicText(
            $image,
            'فاتورة رقمية ذكية',
            100,
            558,
            12,
            $greenDark,
            true,
            'left'
        );

        $this->drawText(
            $image,
            'Secure • Fast • Paperless',
            1095,
            548,
            13,
            $muted,
            false,
            'right'
        );

        /*
         * Footer.
         */
        $this->drawText(
            $image,
            'Powered by',
            78,
            583,
            13,
            $muted
        );

        $this->drawText(
            $image,
            'VENO POS',
            185,
            583,
            15,
            $green,
            true
        );

        $this->drawText(
            $image,
            'Smart Cloud POS & ERP System',
            1120,
            583,
            13,
            $muted,
            false,
            'right'
        );

        ob_start();

        imagepng(
            $image,
            null,
            7
        );

        $png = ob_get_clean();

        imagedestroy($image);

        if (!$png) {
            throw new \RuntimeException(
                'Could not generate invoice preview PNG.'
            );
        }

        return response($png, 200)
            ->header('Content-Type', 'image/png')
            ->header(
                'Content-Length',
                (string) strlen($png)
            )
            ->header(
                'Cache-Control',
                'no-store, no-cache, must-revalidate'
            )
            ->header('Pragma', 'no-cache')
            ->header('Expires', '0');
    }

    private function addBusinessLogo(
        $canvas,
        $business,
        $x,
        $y,
        $boxWidth,
        $boxHeight
    ) {
        if (empty($business) || empty($business->logo)) {
            return false;
        }

        $logoPath = public_path(
            'uploads/business_logos/' . basename($business->logo)
        );

        if (!is_file($logoPath) || !is_readable($logoPath)) {
            return false;
        }

        try {
            $contents = file_get_contents($logoPath);

            if ($contents === false) {
                return false;
            }

            $logo = @imagecreatefromstring($contents);

            if (!$logo) {
                return false;
            }

            imagealphablending($logo, true);
            imagesavealpha($logo, true);

            $sourceWidth = imagesx($logo);
            $sourceHeight = imagesy($logo);

            if ($sourceWidth < 1 || $sourceHeight < 1) {
                imagedestroy($logo);
                return false;
            }

            $ratio = min(
                $boxWidth / $sourceWidth,
                $boxHeight / $sourceHeight
            );

            $targetWidth = max(
                1,
                (int) round($sourceWidth * $ratio)
            );

            $targetHeight = max(
                1,
                (int) round($sourceHeight * $ratio)
            );

            $targetX = $x + (int) (($boxWidth - $targetWidth) / 2);
            $targetY = $y + (int) (($boxHeight - $targetHeight) / 2);

            imagecopyresampled(
                $canvas,
                $logo,
                $targetX,
                $targetY,
                0,
                0,
                $targetWidth,
                $targetHeight,
                $sourceWidth,
                $sourceHeight
            );

            imagedestroy($logo);

            return true;
        } catch (\Throwable $e) {
            return false;
        }
    }

    /**
     * Draw text across one or two lines and reduce font size automatically.
     */
    private function drawFittedMultilineText(
        $image,
        $text,
        $x,
        $y,
        $maxWidth,
        $maxHeight,
        $startSize,
        $minimumSize,
        $color,
        $bold = false,
        $maximumLines = 2
    ) {
        $text = trim((string) $text);

        if ($text === '') {
            return;
        }

        $font = $this->findFont($bold);

        if (!$font || !function_exists('imagettfbbox')) {
            $this->drawText(
                $image,
                mb_substr($text, 0, 36),
                $x,
                $y,
                20,
                $color,
                $bold
            );

            return;
        }

        for ($size = $startSize; $size >= $minimumSize; $size--) {
            $lines = $this->wrapTextForWidth(
                $text,
                $font,
                $size,
                $maxWidth,
                $maximumLines
            );

            $lineHeight = (int) round($size * 1.35);
            $requiredHeight = count($lines) * $lineHeight;

            $fitsWidth = true;

            foreach ($lines as $line) {
                $box = imagettfbbox($size, 0, $font, $line);
                $lineWidth = abs($box[4] - $box[0]);

                if ($lineWidth > $maxWidth) {
                    $fitsWidth = false;
                    break;
                }
            }

            if ($fitsWidth && $requiredHeight <= $maxHeight) {
                foreach ($lines as $index => $line) {
                    $this->drawText(
                        $image,
                        $line,
                        $x,
                        $y + ($index * $lineHeight),
                        $size,
                        $color,
                        $bold
                    );
                }

                return;
            }
        }

        $fallback = mb_substr($text, 0, 42);

        if (mb_strlen($text) > 42) {
            $fallback .= '...';
        }

        $this->drawText(
            $image,
            $fallback,
            $x,
            $y,
            $minimumSize,
            $color,
            $bold
        );
    }

    private function wrapTextForWidth(
        $text,
        $font,
        $fontSize,
        $maxWidth,
        $maximumLines
    ) {
        $words = preg_split('/\s+/u', trim($text));
        $lines = [];
        $current = '';

        foreach ($words as $word) {
            $candidate = $current === ''
                ? $word
                : $current . ' ' . $word;

            $box = imagettfbbox(
                $fontSize,
                0,
                $font,
                $candidate
            );

            $candidateWidth = abs($box[4] - $box[0]);

            if ($candidateWidth <= $maxWidth) {
                $current = $candidate;
                continue;
            }

            if ($current !== '') {
                $lines[] = $current;
                $current = $word;
            } else {
                $lines[] = $word;
                $current = '';
            }

            if (count($lines) >= $maximumLines) {
                break;
            }
        }

        if (
            $current !== '' &&
            count($lines) < $maximumLines
        ) {
            $lines[] = $current;
        }

        $consumed = implode(' ', $lines);

        if (
            mb_strlen($consumed) < mb_strlen($text) &&
            !empty($lines)
        ) {
            $lastIndex = count($lines) - 1;
            $lines[$lastIndex] = rtrim(
                mb_substr($lines[$lastIndex], 0, 28)
            ) . '...';
        }

        return array_slice($lines, 0, $maximumLines);
    }

    /**
     * Use Cairo Regular for every text element in the
     * WhatsApp invoice preview, including headings.
     */
    /**
     * Use Cairo Regular for Arabic and English.
     */
    private function findFont($bold = false)
    {
        $fonts = [
            resource_path('fonts/Cairo-Regular.ttf'),
            public_path('fonts/Cairo-Regular.ttf'),
            '/usr/share/fonts/truetype/cairo/Cairo-Regular.ttf',
            '/usr/share/fonts/Cairo-Regular.ttf',
        ];

        foreach ($fonts as $font) {
            if (
                is_file($font) &&
                is_readable($font)
            ) {
                return $font;
            }
        }

        return null;
    }

    private function drawArabicText(
        $image,
        $text,
        $x,
        $y,
        $size,
        $color,
        $bold = false,
        $align = 'right'
    ) {
        $text = $this->shapeArabicText(
            (string) $text
        );

        $this->drawText(
            $image,
            $text,
            $x,
            $y,
            $size,
            $color,
            $bold,
            $align
        );
    }

    /**
     * Basic Arabic joining and RTL shaping for GD/FreeType.
     */
    private function shapeArabicText($text)
    {
        $forms = [
            'ء' => ['ﺀ'],
            'آ' => ['ﺁ', 'ﺂ'],
            'أ' => ['ﺃ', 'ﺄ'],
            'ؤ' => ['ﺅ', 'ﺆ'],
            'إ' => ['ﺇ', 'ﺈ'],
            'ئ' => ['ﺉ', 'ﺊ', 'ﺋ', 'ﺌ'],
            'ا' => ['ﺍ', 'ﺎ'],
            'ب' => ['ﺏ', 'ﺐ', 'ﺑ', 'ﺒ'],
            'ة' => ['ﺓ', 'ﺔ'],
            'ت' => ['ﺕ', 'ﺖ', 'ﺗ', 'ﺘ'],
            'ث' => ['ﺙ', 'ﺚ', 'ﺛ', 'ﺜ'],
            'ج' => ['ﺝ', 'ﺞ', 'ﺟ', 'ﺠ'],
            'ح' => ['ﺡ', 'ﺢ', 'ﺣ', 'ﺤ'],
            'خ' => ['ﺥ', 'ﺦ', 'ﺧ', 'ﺨ'],
            'د' => ['ﺩ', 'ﺪ'],
            'ذ' => ['ﺫ', 'ﺬ'],
            'ر' => ['ﺭ', 'ﺮ'],
            'ز' => ['ﺯ', 'ﺰ'],
            'س' => ['ﺱ', 'ﺲ', 'ﺳ', 'ﺴ'],
            'ش' => ['ﺵ', 'ﺶ', 'ﺷ', 'ﺸ'],
            'ص' => ['ﺹ', 'ﺺ', 'ﺻ', 'ﺼ'],
            'ض' => ['ﺽ', 'ﺾ', 'ﺿ', 'ﻀ'],
            'ط' => ['ﻁ', 'ﻂ', 'ﻃ', 'ﻄ'],
            'ظ' => ['ﻅ', 'ﻆ', 'ﻇ', 'ﻈ'],
            'ع' => ['ﻉ', 'ﻊ', 'ﻋ', 'ﻌ'],
            'غ' => ['ﻍ', 'ﻎ', 'ﻏ', 'ﻐ'],
            'ف' => ['ﻑ', 'ﻒ', 'ﻓ', 'ﻔ'],
            'ق' => ['ﻕ', 'ﻖ', 'ﻗ', 'ﻘ'],
            'ك' => ['ﻙ', 'ﻚ', 'ﻛ', 'ﻜ'],
            'ل' => ['ﻝ', 'ﻞ', 'ﻟ', 'ﻠ'],
            'م' => ['ﻡ', 'ﻢ', 'ﻣ', 'ﻤ'],
            'ن' => ['ﻥ', 'ﻦ', 'ﻧ', 'ﻨ'],
            'ه' => ['ﻩ', 'ﻪ', 'ﻫ', 'ﻬ'],
            'و' => ['ﻭ', 'ﻮ'],
            'ى' => ['ﻯ', 'ﻰ'],
            'ي' => ['ﻱ', 'ﻲ', 'ﻳ', 'ﻴ'],
        ];

        $chars = mb_str_split(
            trim((string) $text)
        );

        $count = count($chars);
        $result = [];

        for ($i = 0; $i < $count; $i++) {
            $char = $chars[$i];

            if (!isset($forms[$char])) {
                $result[] = $char;
                continue;
            }

            $previous = $chars[$i - 1] ?? null;
            $next = $chars[$i + 1] ?? null;

            $currentForms = $forms[$char];

            $canJoinPrevious =
                $previous !== null &&
                isset($forms[$previous][2]) &&
                isset($currentForms[1]);

            $canJoinNext =
                $next !== null &&
                isset($currentForms[2]) &&
                isset($forms[$next][1]);

            if (
                $canJoinPrevious &&
                $canJoinNext &&
                isset($currentForms[3])
            ) {
                $result[] = $currentForms[3];
            } elseif (
                $canJoinPrevious &&
                isset($currentForms[1])
            ) {
                $result[] = $currentForms[1];
            } elseif (
                $canJoinNext &&
                isset($currentForms[2])
            ) {
                $result[] = $currentForms[2];
            } else {
                $result[] = $currentForms[0];
            }
        }

        return implode(
            '',
            array_reverse($result)
        );
    }

    private function drawText(
        $image,
        $text,
        $x,
        $y,
        $size,
        $color,
        $bold = false,
        $align = 'left'
    ) {
        $font = $this->findFont($bold);

        $text = (string) $text;

        if ($font && function_exists('imagettftext')) {
            $box = imagettfbbox(
                $size,
                0,
                $font,
                $text
            );

            $textWidth = abs($box[4] - $box[0]);

            if ($align === 'center') {
                $x -= (int) ($textWidth / 2);
            } elseif ($align === 'right') {
                $x -= $textWidth;
            }

            imagettftext(
                $image,
                $size,
                0,
                (int) $x,
                (int) $y,
                $color,
                $font,
                $text
            );

            return;
        }

        $fallbackFont = 5;
        $textWidth = imagefontwidth($fallbackFont) * strlen($text);

        if ($align === 'center') {
            $x -= (int) ($textWidth / 2);
        } elseif ($align === 'right') {
            $x -= $textWidth;
        }

        imagestring(
            $image,
            $fallbackFont,
            (int) $x,
            (int) ($y - 18),
            $text,
            $color
        );
    }

    private function roundedRectangle(
        $image,
        $x1,
        $y1,
        $x2,
        $y2,
        $radius,
        $color
    ) {
        imagefilledrectangle(
            $image,
            $x1 + $radius,
            $y1,
            $x2 - $radius,
            $y2,
            $color
        );

        imagefilledrectangle(
            $image,
            $x1,
            $y1 + $radius,
            $x2,
            $y2 - $radius,
            $color
        );

        imagefilledellipse(
            $image,
            $x1 + $radius,
            $y1 + $radius,
            $radius * 2,
            $radius * 2,
            $color
        );

        imagefilledellipse(
            $image,
            $x2 - $radius,
            $y1 + $radius,
            $radius * 2,
            $radius * 2,
            $color
        );

        imagefilledellipse(
            $image,
            $x1 + $radius,
            $y2 - $radius,
            $radius * 2,
            $radius * 2,
            $color
        );

        imagefilledellipse(
            $image,
            $x2 - $radius,
            $y2 - $radius,
            $radius * 2,
            $radius * 2,
            $color
        );
    }

    private function allocate($image, $hex)
    {
        $hex = ltrim($hex, '#');

        if (strlen($hex) === 3) {
            $hex =
                $hex[0] . $hex[0] .
                $hex[1] . $hex[1] .
                $hex[2] . $hex[2];
        }

        return imagecolorallocate(
            $image,
            hexdec(substr($hex, 0, 2)),
            hexdec(substr($hex, 2, 2)),
            hexdec(substr($hex, 4, 2))
        );
    }

    private function cleanText($value, $limit = 50)
    {
        $value = trim(strip_tags((string) $value));
        $value = preg_replace('/\s+/u', ' ', $value);

        return mb_substr($value, 0, $limit);
    }

    private function fallbackResponse($transaction)
    {
        $business = $transaction->business;

        if (!empty($business) && !empty($business->logo)) {
            $logoPath = public_path(
                'uploads/business_logos/' . basename($business->logo)
            );

            if (is_file($logoPath) && is_readable($logoPath)) {
                $contents = file_get_contents($logoPath);

                if ($contents !== false) {
                    $mime = mime_content_type($logoPath)
                        ?: 'image/png';

                    return response($contents, 200)
                        ->header('Content-Type', $mime)
                        ->header('Cache-Control', 'no-cache');
                }
            }
        }

        abort(500, 'Invoice preview could not be generated.');
    }

    private function writeErrorLog(\Throwable $e, $token)
    {
        try {
            $logDir = storage_path('logs');

            if (!is_dir($logDir)) {
                mkdir($logDir, 0755, true);
            }

            file_put_contents(
                $logDir . '/veno_invoice_preview.log',
                '[' . date('Y-m-d H:i:s') . '] '
                . 'Token: ' . $token
                . ' | Error: ' . $e->getMessage()
                . ' | File: ' . $e->getFile()
                . ' | Line: ' . $e->getLine()
                . PHP_EOL,
                FILE_APPEND
            );
        } catch (\Throwable $ignored) {
            // لا نوقف الصورة بسبب فشل تسجيل الخطأ.
        }
    }
}
