<?php
declare(strict_types=1);

namespace Itdatex\EInvoiceCore;

use Itdatex\EInvoiceCore\Vendor\horstoeko\zugferd\ZugferdDocumentPdfBuilder;

/**
 * Erzeugt eine hybride ZUGFeRD-PDF: schlanke A4-Rechnung visuell via FPDF
 * + eingebettete CII-XML (EN 16931) via ZugferdDocumentPdfBuilder.
 *
 * Output: PDF-Bytes (string). PDF/A-3 mit Anhang "factur-x.xml" oder
 * "zugferd-invoice.xml" — wie der horstoeko-Builder es defaultmaessig macht.
 *
 * Layout absichtlich nuechtern: Logo waere optional, KoSIT prueft nur das
 * XML, nicht das Visuelle. Wer mehr Optik will, ersetzt diese Klasse oder
 * fuettert ZugferdDocumentPdfBuilder mit einer extern gerenderten PDF.
 */
final class ZugferdPdfBuilder
{
    private CiiBuilder $ciiBuilder;

    public function __construct( ?CiiBuilder $ciiBuilder = null )
    {
        $this->ciiBuilder = $ciiBuilder ?? new CiiBuilder();
    }

    public function build( InvoiceDraft $draft ): string
    {
        // 1) Visuelle PDF zeichnen
        $pdfBytes = $this->renderVisualPdf( $draft );

        // 2) CII-Builder fuer's Embedden
        $ciiDocBuilder = $this->ciiBuilder->buildBuilder( $draft );

        // 3) PDF + CII zusammenfuehren
        $hybrid = ZugferdDocumentPdfBuilder::fromPdfString( $ciiDocBuilder, $pdfBytes );
        $hybrid->generateDocument();
        return $hybrid->downloadString();
    }

    private function renderVisualPdf( InvoiceDraft $draft ): string
    {
        $pdf = new \Itdatex_EInvoiceCore_Vendor_FPDF( 'P', 'mm', 'A4' );
        $pdf->SetAutoPageBreak( true, 20 );
        $pdf->SetMargins( 20, 15, 20 );
        $pdf->AddPage();

        // ----- Verkaeufer-Block oben links -----
        $pdf->SetFont( 'Helvetica', 'B', 11 );
        $pdf->Cell( 0, 6, self::enc( $draft->seller->name ), 0, 1 );
        $pdf->SetFont( 'Helvetica', '', 9 );
        foreach ( $draft->seller->addressLines as $line ) {
            $pdf->Cell( 0, 4.5, self::enc( $line ), 0, 1 );
        }
        $zip = trim( ( $draft->seller->postalCode ?? '' ) . ' ' . ( $draft->seller->city ?? '' ) );
        if ( $zip !== '' ) {
            $pdf->Cell( 0, 4.5, self::enc( $zip ), 0, 1 );
        }
        if ( $draft->seller->countryCode !== null ) {
            $pdf->Cell( 0, 4.5, self::enc( $draft->seller->countryCode ), 0, 1 );
        }
        $pdf->Ln( 4 );

        // ----- Header rechts: RECHNUNG + Meta -----
        $pdf->SetXY( 130, 15 );
        $pdf->SetFont( 'Helvetica', 'B', 18 );
        $pdf->Cell( 60, 10, self::enc( 'Rechnung' ), 0, 2, 'R' );
        $pdf->SetFont( 'Helvetica', '', 9 );
        $pdf->Cell( 60, 5, self::enc( 'Nr. ' . $draft->invoiceNumber ),                            0, 2, 'R' );
        $pdf->Cell( 60, 5, self::enc( 'Datum: ' . $draft->issueDate->format( 'd.m.Y' ) ),          0, 2, 'R' );
        if ( $draft->dueDate !== null ) {
            $pdf->Cell( 60, 5, self::enc( 'Faellig: ' . $draft->dueDate->format( 'd.m.Y' ) ),     0, 2, 'R' );
        }
        if ( $draft->deliveryDate !== null ) {
            $pdf->Cell( 60, 5, self::enc( 'Lieferdatum: ' . $draft->deliveryDate->format( 'd.m.Y' ) ), 0, 2, 'R' );
        }
        if ( $draft->buyerReference !== null && $draft->buyerReference !== '' ) {
            $pdf->Cell( 60, 5, self::enc( 'Leitweg-ID: ' . $draft->buyerReference ),               0, 2, 'R' );
        }

        // ----- Kaeufer-Block links unter Verkaeufer (Anschriftenfeld) -----
        $pdf->SetXY( 20, 55 );
        $pdf->SetFont( 'Helvetica', 'B', 10 );
        $pdf->Cell( 0, 5, self::enc( $draft->buyer->name ), 0, 1 );
        $pdf->SetFont( 'Helvetica', '', 10 );
        foreach ( $draft->buyer->addressLines as $line ) {
            $pdf->Cell( 0, 5, self::enc( $line ), 0, 1 );
        }
        $bzip = trim( ( $draft->buyer->postalCode ?? '' ) . ' ' . ( $draft->buyer->city ?? '' ) );
        if ( $bzip !== '' ) {
            $pdf->Cell( 0, 5, self::enc( $bzip ), 0, 1 );
        }
        if ( $draft->buyer->countryCode !== null ) {
            $pdf->Cell( 0, 5, self::enc( $draft->buyer->countryCode ), 0, 1 );
        }
        $pdf->Ln( 10 );

        // ----- Optionale Notiz oberhalb der Positionen -----
        if ( $draft->note !== null && $draft->note !== '' ) {
            $pdf->SetFont( 'Helvetica', 'I', 9 );
            $pdf->MultiCell( 0, 5, self::enc( $draft->note ) );
            $pdf->Ln( 2 );
        }

        // ----- Positionen-Tabelle -----
        $pdf->SetFont( 'Helvetica', 'B', 9 );
        $pdf->SetFillColor( 235, 235, 235 );
        $pdf->Cell(  8, 7, self::enc( '#' ),               'B', 0, 'C', true );
        $pdf->Cell( 80, 7, self::enc( 'Position' ),        'B', 0, 'L', true );
        $pdf->Cell( 18, 7, self::enc( 'Menge' ),           'B', 0, 'R', true );
        $pdf->Cell( 14, 7, self::enc( 'Einh.' ),           'B', 0, 'C', true );
        $pdf->Cell( 22, 7, self::enc( 'Einzelpreis' ),     'B', 0, 'R', true );
        $pdf->Cell( 12, 7, self::enc( 'MwSt' ),            'B', 0, 'R', true );
        $pdf->Cell( 26, 7, self::enc( 'Zeilensumme' ),     'B', 1, 'R', true );

        $pdf->SetFont( 'Helvetica', '', 9 );
        $lineTotal      = 0.0;
        $taxByRate      = [];
        foreach ( $draft->lines as $i => $line ) {
            $rowNet = round( $line->quantity * $line->unitPrice, 2 );
            $lineTotal += $rowNet;
            $rateKey = number_format( $line->vatRate, 2, '.', '' );
            $taxByRate[ $rateKey ] = ( $taxByRate[ $rateKey ] ?? 0.0 ) + $rowNet;

            $pdf->Cell(  8, 6, self::enc( (string) ( $i + 1 ) ),               'B', 0, 'C' );
            $pdf->Cell( 80, 6, self::enc( $line->name ),                       'B', 0, 'L' );
            $pdf->Cell( 18, 6, self::enc( self::numFmt( $line->quantity, 2 ) ), 'B', 0, 'R' );
            $pdf->Cell( 14, 6, self::enc( $line->unitCode ),                   'B', 0, 'C' );
            $pdf->Cell( 22, 6, self::enc( self::numFmt( $line->unitPrice, 2 ) ), 'B', 0, 'R' );
            $pdf->Cell( 12, 6, self::enc( self::numFmt( $line->vatRate, 0 ) . '%' ), 'B', 0, 'R' );
            $pdf->Cell( 26, 6, self::enc( self::numFmt( $rowNet, 2 ) ),        'B', 1, 'R' );
        }

        $pdf->Ln( 4 );

        // ----- Summenblock rechts -----
        $taxTotal = 0.0;
        $pdf->SetFont( 'Helvetica', '', 10 );
        $pdf->Cell( 124, 6, '', 0, 0 );
        $pdf->Cell(  36, 6, self::enc( 'Netto' ),                              0, 0, 'R' );
        $pdf->Cell(  20, 6, self::enc( self::numFmt( $lineTotal, 2 ) ),        0, 1, 'R' );
        foreach ( $taxByRate as $rateKey => $base ) {
            $rate = (float) $rateKey;
            $tax  = round( $base * $rate / 100, 2 );
            $taxTotal += $tax;
            $pdf->Cell( 124, 6, '', 0, 0 );
            $pdf->Cell(  36, 6, self::enc( 'MwSt ' . self::numFmt( $rate, 0 ) . '%' ), 0, 0, 'R' );
            $pdf->Cell(  20, 6, self::enc( self::numFmt( $tax, 2 ) ),                  0, 1, 'R' );
        }
        $pdf->SetFont( 'Helvetica', 'B', 11 );
        $grand = round( $lineTotal + $taxTotal, 2 );
        $pdf->Cell( 124, 7, '', 0, 0 );
        $pdf->Cell(  36, 7, self::enc( 'Brutto ' . $draft->currency ),         'T', 0, 'R' );
        $pdf->Cell(  20, 7, self::enc( self::numFmt( $grand, 2 ) ),            'T', 1, 'R' );

        $pdf->Ln( 8 );

        // ----- Zahlungsblock -----
        if ( $draft->paymentIban !== null && $draft->paymentIban !== '' ) {
            $pdf->SetFont( 'Helvetica', 'B', 9 );
            $pdf->Cell( 0, 5, self::enc( 'Bankverbindung' ), 0, 1 );
            $pdf->SetFont( 'Helvetica', '', 9 );
            $pdf->Cell( 0, 5, self::enc( 'IBAN: ' . $draft->paymentIban ), 0, 1 );
            if ( $draft->paymentBic !== null && $draft->paymentBic !== '' ) {
                $pdf->Cell( 0, 5, self::enc( 'BIC: ' . $draft->paymentBic ), 0, 1 );
            }
            $pdf->Ln( 1 );
        }
        if ( $draft->paymentTerms !== null && $draft->paymentTerms !== '' ) {
            $pdf->SetFont( 'Helvetica', '', 9 );
            $pdf->MultiCell( 0, 5, self::enc( $draft->paymentTerms ) );
        }

        // ----- Footer-Hinweis -----
        $pdf->SetY( -25 );
        $pdf->SetFont( 'Helvetica', 'I', 7 );
        $pdf->Cell( 0, 4, self::enc(
            'Diese Rechnung ist eine hybride ZUGFeRD/Factur-X-Datei (EN 16931). '
            . 'Die strukturierten Daten sind als XML-Anhang in dieser PDF eingebettet.'
        ), 0, 1, 'C' );

        $output = $pdf->Output( 'S' );
        return is_string( $output ) ? $output : (string) $output;
    }

    /** FPDF erwartet CP1252/latin1 — UTF-8-Umlaute konvertieren. */
    private static function enc( string $s ): string
    {
        // mb_convert_encoding ist verlaesslicher als utf8_decode (deprecated in PHP 8.2)
        if ( function_exists( 'mb_convert_encoding' ) ) {
            $r = @\mb_convert_encoding( $s, 'CP1252', 'UTF-8' );
            return is_string( $r ) ? $r : $s;
        }
        return $s;
    }

    private static function numFmt( float $value, int $decimals ): string
    {
        return number_format( $value, $decimals, ',', '.' );
    }
}
