<?php

declare(strict_types=1);

namespace App\Services;

use App\Repositories\InvoiceRepository;
use App\Repositories\PaymentRepository;
use App\Repositories\ReportRepository;
use App\Services\SettingsService;
use Dompdf\Dompdf;
use Dompdf\Options;
use RuntimeException;

final class PdfService
{
    public function __construct(
        private ?InvoiceRepository $invoices = null,
        private ?PaymentRepository $payments = null,
        private ?ReportRepository $reports = null,
        private ?SettingsService $settings = null,
    ) {
        $this->invoices ??= new InvoiceRepository();
        $this->payments ??= new PaymentRepository();
        $this->reports ??= new ReportRepository();
        $this->settings ??= new SettingsService();
    }

    public function invoice(int $id): array
    {
        $invoice = $this->invoices->find($id);
        if (!$invoice) throw new RuntimeException('Invoice not found.', 404);
        $invoice['items'] = $this->invoices->items($id);
        $invoice['paid_amount'] = $this->payments->activePaidTotal($id);
        $invoice['balance'] = max(0, (float)$invoice['total'] - (float)$invoice['paid_amount']);
        $invoice['business'] = $this->business();
        return $invoice;
    }

    public function receipt(int $paymentId): array
    {
        $payment = $this->payments->find($paymentId);
        if (!$payment) throw new RuntimeException('Payment not found.', 404);
        $invoice = $this->payments->invoice((int)$payment['invoice_id']);
        if (!$invoice) throw new RuntimeException('Invoice not found.', 404);
        $payments = $this->payments->invoicePayments((int)$payment['invoice_id']);
        $receipt = null;
        foreach ($payments as $row) {
            if ((int)$row['id'] === $paymentId) {
                $receipt = $row['receipt_number'] ?? null;
                break;
            }
        }
        if (!$receipt) throw new RuntimeException('Receipt not found for this payment.', 404);
        $invoice['paid_amount'] = $this->payments->activePaidTotal((int)$payment['invoice_id']);
        $invoice['balance'] = max(0, (float)$invoice['total'] - (float)$invoice['paid_amount']);
        return ['payment' => $payment, 'invoice' => $invoice, 'receipt_number' => $receipt, 'business' => $this->business()];
    }


    public function assessment(int $id): array
    {
        $stmt=\App\Core\Database::connection()->prepare("SELECT a.*,sv.name AS service_name,sv.price AS service_price,p.patient_reference,p.first_name,p.last_name,u.full_name AS therapist_name FROM assessments a INNER JOIN patients p ON p.id=a.patient_id INNER JOIN therapists t ON t.id=a.therapist_id INNER JOIN users u ON u.id=t.user_id LEFT JOIN services sv ON sv.id=a.service_id WHERE a.id=:id LIMIT 1");
        $stmt->execute(['id'=>$id]); $assessment=$stmt->fetch(); if(!is_array($assessment))throw new RuntimeException('Assessment not found.',404);
        if(($assessment['status']??'')!=='approved')throw new RuntimeException('Only approved assessments can be generated as official PDFs.',403);
        return ['assessment'=>$assessment,'business'=>$this->business()];
    }

    public function report(int $id): array
    {
        $report = $this->reports->find($id);
        if (!$report) throw new RuntimeException('Clinical report not found.', 404);
        if (($report['status'] ?? '') !== 'approved') {
            throw new RuntimeException('Only approved clinical reports can be generated as official PDFs.', 403);
        }
        $version = $this->reports->currentVersion($id);
        if (!$version) throw new RuntimeException('Approved report version not found.', 404);
        $content = json_decode((string)$version['content'], true);
        if (!is_array($content)) $content = [];
        return ['report' => $report, 'version' => $version, 'content' => $content, 'business' => $this->business()];
    }

    private function business(): array
    {
        $all = $this->settings->get();
        $get = static fn(string $key, string $fallback = '') => (string)($all[$key]['value'] ?? $fallback);
        $logo = '';
        $logoFile = $get('business.logo');
        if ($logoFile !== '') {
            $safe = basename($logoFile);
            $path = dirname(__DIR__, 2) . '/storage/branding/' . $safe;
            if (is_file($path)) {
                $mime = $safe !== '' && str_ends_with(strtolower($safe), '.png') ? 'image/png' : 'image/jpeg';
                $logo = 'data:' . $mime . ';base64,' . base64_encode((string) file_get_contents($path));
            }
        }
        return [
            'name' => $get('business.name', 'Grow Tool Therapies'),
            'tagline' => $get('business.tagline', 'Occupational Therapy Services'),
            'email' => $get('business.email'),
            'phone' => $get('business.phone'),
            'address' => $get('business.address'),
            'website' => $this->normalizeWebsite($get('business.website')),
            'country' => $get('business.country'),
            'currency' => $get('regional.currency_symbol', 'KSh'),
            'logo' => $logo,
        ];
    }

    private function normalizeWebsite(string $website): string
    {
        $website = trim($website);
        if ($website === '') return '';
        return preg_replace('#^https?://#i', '', rtrim($website, '/')) ?: $website;
    }

    public function render(string $template, array $data): string
    {
        $view = dirname(__DIR__, 2) . '/resources/views/pdf/' . $template . '.php';
        if (!is_file($view)) throw new RuntimeException('PDF template not found.');
        extract($data, EXTR_SKIP);
        ob_start();
        require $view;
        $html = (string)ob_get_clean();

        $options = new Options();
        $options->set('isRemoteEnabled', false);
        $options->set('defaultFont', 'DejaVu Sans');
        $dompdf = new Dompdf($options);
        $dompdf->loadHtml($html, 'UTF-8');
        $dompdf->setPaper('A4', 'portrait');
        $dompdf->render();
        return $dompdf->output();
    }
}
