<?php

namespace App\Core\Services\Receipt;

use App\Models\CompanySetting;
use App\Models\Currency;
use App\Models\Receipt;
use App\Support\ReceiptTemplateResolver;
use Dompdf\Dompdf;
use Dompdf\Options;
use Illuminate\Support\Facades\View;

/**
 * Payment receipt PDFs: per-template pdf.blade.php (Dompdf) or simple receipt.pdf.
 */
class ReceiptPdfService
{
    /**
     * @return object Payment-shaped DTO expected by receipt template blades
     */
    public static function mapToPayment(Receipt $receipt): object
    {
        $receipt->loadMissing(['invoice', 'customer']);
        $invoice = $receipt->invoice;
        $currency = $invoice ? $invoice->currency : Currency::getDefaultCode();

        return (object) [
            'payment_number' => $receipt->receipt_number,
            'payment_date' => $receipt->created_at,
            'payment_method' => $receipt->payment_method,
            'amount' => $receipt->amount,
            'currency' => $currency,
            'transaction_id' => $receipt->transaction_reference,
            'reference' => $receipt->transaction_reference,
            'notes' => $receipt->notes,
            'customer' => $receipt->customer,
            'invoice' => $invoice,
        ];
    }

    /**
     * @param  string|null  $templateKeyOverride  Force template key (e.g. admin ?template=); null = use receipt row + company default
     */
    public function generate(Receipt $receipt, ?string $templateKeyOverride = null, bool $simpleLayout = false): string
    {
        $receipt->load(['invoice', 'customer']);

        $publicRoot = realpath(public_path());
        if ($publicRoot === false) {
            $publicRoot = public_path();
        }
        $storagePublicRoot = realpath(storage_path('app/public'));
        $chroot = array_values(array_unique(array_filter([$publicRoot, $storagePublicRoot !== false ? $storagePublicRoot : null])));

        $options = new Options;
        $options->set('isHtml5ParserEnabled', true);
        $options->set('isRemoteEnabled', true);
        $options->set('defaultFont', 'DejaVu Sans');
        $options->setChroot($chroot);

        $dompdf = new Dompdf($options);

        if ($simpleLayout && View::exists('receipt.pdf')) {
            $company = CompanySetting::getSettings();
            $html = View::make('receipt.pdf', [
                'receipt' => $receipt,
                'payment' => self::mapToPayment($receipt),
                'company' => $company,
            ])->render();
        } else {
            $key = (is_string($templateKeyOverride) && $templateKeyOverride !== '')
                ? ReceiptTemplateResolver::normalize($templateKeyOverride)
                : ReceiptTemplateResolver::resolveKeyForReceipt($receipt);
            $pdfView = ReceiptTemplateResolver::pdfView($key);
            $html = view($pdfView, [
                'payment' => self::mapToPayment($receipt),
            ])->render();
        }

        $html = self::rewriteStorageImageSrcsForDompdf($html, $publicRoot);

        $dompdf->loadHtml($html);
        $dompdf->setPaper([0.0, 0.0, 595.28, 841.89], 'portrait');
        $dompdf->render();

        return $dompdf->output();
    }

    public function download(Receipt $receipt, ?string $templateKeyOverride = null, bool $simpleLayout = false): \Symfony\Component\HttpFoundation\Response
    {
        $pdf = $this->generate($receipt, $templateKeyOverride, $simpleLayout);
        $filename = 'receipt-'.$receipt->receipt_number.'.pdf';

        return response()->streamDownload(function () use ($pdf) {
            echo $pdf;
        }, $filename, [
            'Content-Type' => 'application/pdf',
        ]);
    }

    private static function rewriteStorageImageSrcsForDompdf(string $html, string $publicRoot): string
    {
        return preg_replace_callback(
            '#\bsrc=(["\'])([^"\']+)\1#i',
            static function (array $m) use ($publicRoot) {
                $q = $m[1];
                $src = $m[2];
                $relativeStorage = null;
                if (str_starts_with($src, '/storage/')) {
                    $relativeStorage = ltrim($src, '/');
                } elseif (preg_match('#^https?://[^/]+(/storage/.+)$#i', $src, $mm)) {
                    $relativeStorage = ltrim($mm[1], '/');
                }
                if ($relativeStorage === null) {
                    return $m[0];
                }
                $full = $publicRoot.DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $relativeStorage);
                $resolved = realpath($full);

                if ($resolved === false || ! is_file($resolved)) {
                    return $m[0];
                }

                return 'src='.$q.self::absolutePathToFileUri($resolved).$q;
            },
            $html
        );
    }

    private static function absolutePathToFileUri(string $absolutePath): string
    {
        $path = str_replace('\\', '/', $absolutePath);
        $path = str_replace(' ', '%20', $path);

        return preg_match('#^[A-Za-z]:/#', $path) === 1
            ? 'file:///'.$path
            : 'file://'.$path;
    }
}
