<?php

namespace App\Services;

class InvoicePdfGenerator
{
    private $width = 595;
    private $height = 842;
    private $margin = 40;

    public function generate($client, $payment, $registration)
    {
        $pdf = $this->createInvoicePdf($client, $payment, $registration);
        return $pdf;
    }

    private function createInvoicePdf($client, $payment, $registration)
    {
        // Build content streams
        $pageContent = $this->buildPageContent($client, $payment, $registration);

        // Create PDF document
        $pdf = $this->assemblePdf($pageContent);

        return $pdf;
    }

    private function buildPageContent($client, $payment, $registration)
    {
        $ops = [];

        // Helper to add text
        $addText = function ($text, $x, $y, $fontSize = 12, $bold = false, $color = 'black') use (&$ops) {
            $font = $bold ? '/F2' : '/F1';
            $rgb = $this->getColor($color);
            $ops[] = "q"; // Save graphics state
            $ops[] = $rgb;
            $ops[] = "$font {$fontSize} Tf";
            $ops[] = "1 0 0 1 {$x} {$y} Tm"; // Set text matrix (absolute positioning)
            $ops[] = '(' . $this->escape($text) . ') Tj';
            $ops[] = "Q"; // Restore graphics state
        };

        // Starting Y position (from top, going down)
        $y = $this->height - $this->margin - 30;

        // === HEADER ===
        // Company Name (Red)
        $addText('MAY SAFE BOX SDN BHD', $this->margin, $y, 24, true, 'red');

        // Company Address
        $y -= 25;
        $addText('847129-P', $this->margin, $y, 9, false, 'black');
        $y -= 12;
        $addText('NO 198 JALAN TUANKU MUNAWIR 70100 SEREMBAN NSDK', $this->margin, $y, 9, false, 'black');
        $y -= 12;
        $addText('Tel: 06-7632190 / 06-7633190 / 012-5031190', $this->margin, $y, 9, false, 'black');
        // $y -= 12;
        // $addText('Reg No: 202401012345', $this->margin, $y, 9, false, 'black');

        // Invoice Title (Right side)
        $addText('INVOICE', $this->width - $this->margin - 120, $this->height - $this->margin - 30, 36, false, 'lightgray');
        $invoiceNumber = $payment->invoice ? $payment->invoice->invoice_number : 'INV-' . str_pad($payment->id ?? $registration->id, 6, '0', STR_PAD_LEFT);
        $addText("Invoice {$invoiceNumber}", $this->width - $this->margin - 80, $this->height - $this->margin - 65, 12, true, 'black');
        $date = $payment->payment_date ? \Carbon\Carbon::parse($payment->payment_date)->format('d/m/Y') : now()->format('d/m/Y');
        $addText("DATE: {$date}", $this->width - $this->margin - 100, $this->height - $this->margin - 80, 9, false, 'black');

        // Separator line
        $y = $this->height - $this->margin - 130;
        $ops[] = 'q 0.8 0.8 0.8 RG 1 w ' . $this->margin . ' ' . $y . ' m ' . ($this->width - $this->margin) . ' ' . $y . ' l S Q';

        // === BILLED TO ===
        $y -= 30;
        $addText('BILLED TO:', $this->margin, $y, 9, true, 'gray');
        $y -= 18;
        $addText(strtoupper($client->name), $this->margin, $y, 11, true, 'black');
        $y -= 15;
        $addText($client->address, $this->margin, $y, 9, false, 'black');
        $y -= 12;
        $cityState = ($client->cityRel->name ?? '') . ', ' . ($client->stateRel->name ?? '');
        $addText($cityState, $this->margin, $y, 9, false, 'black');
        $y -= 12;
        $addText($client->countryRel->name ?? '', $this->margin, $y, 9, false, 'black');

        // === RIGHT SIDE INFO ===
        $infoX = $this->width - $this->margin - 220;
        $infoY = $this->height - $this->margin - 145;
        $addText('Customer ID: ' . $client->id, $infoX, $infoY, 9, false, 'black');
        $infoY -= 12;
        $plan = $registration->membershipPlan->name ?? 'Standard';
        $addText('Plan Type: ' . $plan, $infoX, $infoY, 9, false, 'black');
        $infoY -= 12;
        $startDate = $registration->contract_start_date ? \Carbon\Carbon::parse($registration->contract_start_date)->format('d-m-Y') : 'N/A';
        $endDate = $registration->contract_end_date ? \Carbon\Carbon::parse($registration->contract_end_date)->format('d-m-Y') : 'N/A';
        $addText('Contract: ' . $startDate . ' to ' . $endDate, $infoX, $infoY, 9, false, 'black');

        // === TABLE HEADER ===
        $y -= 50;
        $tableTop = $y;

        // Background
        $ops[] = 'q 0.95 0.95 0.95 rg ' . $this->margin . ' ' . ($y - 3) . ' ' . ($this->width - 2 * $this->margin) . ' 22 re f Q';

        // Headers
        $addText('Description of Services', $this->margin + 10, $y + 5, 9, true, 'black');
        $addText('Locker Specs', $this->margin + 250, $y + 5, 9, true, 'black');
        $addText('Amount [RM]', $this->width - $this->margin - 100, $y + 5, 9, true, 'black');

        // Border lines
        $ops[] = 'q 0.7 0.7 0.7 RG 0.5 w ' . $this->margin . ' ' . ($y - 5) . ' m ' . ($this->width - $this->margin) . ' ' . ($y - 5) . ' l S Q';
        $ops[] = 'q 0.7 0.7 0.7 RG 0.5 w ' . $this->margin . ' ' . ($y + 20) . ' m ' . ($this->width - $this->margin) . ' ' . ($y + 20) . ' l S Q';

        // === TABLE ITEMS ===
        $y -= 30;

        foreach ($registration->items as $item) {
            $addText('Safe Box Rental', $this->margin + 10, $y, 10, true, 'black');
            $y -= 12;
            $addText('Box Number: ' . $item->locker_number, $this->margin + 10, $y, 8, false, 'gray');
            $addText($item->size . ' / ' . $item->type, $this->margin + 250, $y + 12, 9, false, 'black');
            $addText(number_format($item->amount, 2), $this->width - $this->margin - 80, $y + 12, 9, false, 'black');
            $y -= 20;
        }

        // Bottom line
        $ops[] = 'q 0.7 0.7 0.7 RG 0.5 w ' . $this->margin . ' ' . $y . ' m ' . ($this->width - $this->margin) . ' ' . $y . ' l S Q';

        // === TOTALS SECTION ===
        $y -= 35;
        $totalX = $this->width - $this->margin - 220;


        if ($registration->tax_amount > 0) {
            $addText('Tax', $totalX, $y, 9, false, 'black');
            $addText('RM ' . number_format($registration->tax_amount, 2), $totalX + 120, $y, 9, false, 'black');
            $y -= 15;
        }
        if ($payment->notes !== 'renewal') {

        if ($registration->stamping_fee > 0) {
            $addText('Stamping Fee', $totalX, $y, 9, false, 'black');
            $addText('RM ' . number_format($registration->stamping_fee, 2), $totalX + 120, $y, 9, false, 'black');
            $y -= 15;
        }

        if ($registration->key_deposit > 0) {
            $addText('Key Deposit', $totalX, $y, 9, false, 'black');
            $addText('RM ' . number_format($registration->key_deposit, 2), $totalX + 120, $y, 9, false, 'black');
            $y -= 15;
        }
        }


        if ($registration->insurance_charges > 0) {
            $addText('Insurance', $totalX, $y, 9, false, 'black');
            $addText('RM ' . number_format($registration->insurance_charges, 2), $totalX + 120, $y, 9, false, 'black');
            $y -= 15;
        }

        if ($registration->discount_amount > 0) {
            $addText('Less: Discount', $totalX, $y, 9, false, 'red');
            $addText('- RM ' . number_format($registration->discount_amount, 2), $totalX + 120, $y, 9, false, 'red');
            $y -= 15;
        }

        // Total with background
        $y -= 10;
        $ops[] = 'q 0.95 0.95 0.95 rg ' . $totalX . ' ' . ($y - 5) . ' 200 25 re f Q';
        $addText('Total Amount Paid', $totalX, $y + 5, 11, true, 'black');
        $addText('RM ' . number_format($payment->total_amount, 2), $totalX + 110, $y + 5, 12, true, 'blue');

        // === FOOTER ===
        $y = $this->margin + 50;
        $ops[] = 'q 0.5 0.5 0.5 RG 0.5 w ' . $this->margin . ' ' . ($y + 15) . ' m ' . ($this->width - $this->margin) . ' ' . ($y + 15) . ' l S Q';

        $centerX = $this->width / 2 - 80;
        $addText('Thank you for your business.', $centerX, $y, 8, true, 'gray');
        $y -= 12;
        $addText('This is a computer generated receipt. Signature is not required.', $centerX, $y, 8, false, 'gray');

        return implode("\n", $ops);
    }

    private function getColor($color)
    {
        $colors = [
            'black' => '0 0 0 rg',
            'red' => '1 0 0 rg',
            'gray' => '0.5 0.5 0.5 rg',
            'lightgray' => '0.7 0.7 0.7 rg',
            'blue' => '0 0 0.8 rg'
        ];
        return $colors[$color] ?? $colors['black'];
    }

    private function escape($text)
    {
        return str_replace(['(', ')', '\\', '<', '>'], ['\\(', '\\)', '\\\\', '', ''], $text);
    }

    private function assemblePdf($content)
    {
        $width = $this->width;
        $height = $this->height;

        $pdf = "%PDF-1.4\n";

        // Object 1: Catalog
        $obj1 = "1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n";

        // Object 2: Pages
        $obj2 = "2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n";

        // Object 3: Page
        $obj3 = "3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 {$width} {$height}] /Contents 4 0 R /Resources << /Font << /F1 5 0 R /F2 6 0 R >> /ProcSet [/PDF /Text] >> >>\nendobj\n";

        // Object 4: Content Stream
        $contentStream = $content . "\n";
        $obj4 = "4 0 obj\n<< /Length " . strlen($contentStream) . " >>\nstream\n" . $contentStream . "\nendstream\nendobj\n";

        // Object 5: Helvetica
        $obj5 = "5 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>\nendobj\n";

        // Object 6: Helvetica-Bold
        $obj6 = "6 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold >>\nendobj\n";

        // Build PDF
        $pdf .= $obj1 . $obj2 . $obj3 . $obj4 . $obj5 . $obj6;

        // Calculate offsets
        $offset1 = strlen("%PDF-1.4\n");
        $offset2 = $offset1 + strlen($obj1);
        $offset3 = $offset2 + strlen($obj2);
        $offset4 = $offset3 + strlen($obj3);
        $offset5 = $offset4 + strlen($obj4);
        $offset6 = $offset5 + strlen($obj5);

        // xref table
        $xrefOffset = strlen($pdf);
        $xref = "xref\n0 7\n";
        $xref .= sprintf("%010d 65535 f \n", 0);
        $xref .= sprintf("%010d 00000 n \n", $offset1);
        $xref .= sprintf("%010d 00000 n \n", $offset2);
        $xref .= sprintf("%010d 00000 n \n", $offset3);
        $xref .= sprintf("%010d 00000 n \n", $offset4);
        $xref .= sprintf("%010d 00000 n \n", $offset5);
        $xref .= sprintf("%010d 00000 n \n", $offset6);

        $pdf .= $xref;
        $pdf .= "trailer\n<< /Size 7 /Root 1 0 R >>\nstartxref\n" . $xrefOffset . "\n%%EOF";

        return $pdf;
    }
}
