<?php

/**
 * PDF Generator for KleinBooks
 * Generates professional invoice PDFs using Dompdf
 * Supports ZUGFeRD 2.2 (Factur-X) e-invoicing
 *
 * @since 1.0.0
 * @since 1.4.0 Added ZUGFeRD 2.2 support
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
class KleinBooks_PDF_Generator {
    private static $dompdf_loaded = false;

    /**
     * Load vendor libraries (Dompdf, ZUGFeRD)
     */
    private static function load_dompdf() {
        if ( self::$dompdf_loaded ) {
            return true;
        }
        $autoload = KLEINBOOKS_PLUGIN_DIR . 'vendor/autoload.php';
        if ( file_exists( $autoload ) ) {
            require_once $autoload;
            self::$dompdf_loaded = true;
            return true;
        }
        error_log( '[MK-PDF] Autoload file not found: ' . $autoload );
        return false;
    }

    /**
     * Check if ZUGFeRD is enabled in settings
     *
     * @return bool
     */
    public static function is_zugferd_enabled() {
        $setting = KleinBooks_Database::get_setting( 'zugferd_enabled', '1' );
        // Handle all possible truthy values: '1', 'true', true, 1
        return $setting === '1' || $setting === 1 || $setting === true || $setting === 'true' || $setting === 'on';
    }

    /**
     * Generate PDF for an invoice
     *
     * @param int $invoice_id Invoice ID
     * @param string $output 'stream' (display in browser), 'download', 'save', or 'string' (return PDF content)
     * @return string|void PDF URL if saved, PDF content if string, or streams/downloads directly
     */
    public static function generate( $invoice_id, $output = 'save' ) {
        global $wpdb;
        // Load Dompdf
        if ( !self::load_dompdf() ) {
            throw new Exception('Dompdf library not found');
        }
        $invoices_table = KleinBooks_Database::get_table_name( 'invoices' );
        $invoice_items_table = KleinBooks_Database::get_table_name( 'invoice_items' );
        $clients_table = KleinBooks_Database::get_table_name( 'clients' );
        // Get invoice data
        $invoice = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$invoices_table} WHERE id = %d", $invoice_id ), ARRAY_A );
        if ( !$invoice ) {
            throw new Exception('Invoice not found');
        }
        // Get client data
        $client = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$clients_table} WHERE id = %d", $invoice['client_id'] ), ARRAY_A );
        if ( !$client ) {
            throw new Exception('Client not found');
        }
        // Get invoice items
        $items = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$invoice_items_table} WHERE invoice_id = %d ORDER BY sort_order, id", $invoice_id ), ARRAY_A );
        // Get settings
        $settings = KleinBooks_Database::get_all_settings();
        // Generate HTML from template
        $html = self::render_template(
            $invoice,
            $client,
            $items,
            $settings
        );
        // Create Dompdf instance
        try {
            $options = new \Dompdf\Options();
            $options->set( 'isHtml5ParserEnabled', true );
            $options->set( 'isRemoteEnabled', false );
            $options->set( 'defaultFont', 'DejaVu Sans' );
            // Use DejaVu for better PDF/A-3 compatibility
            $options->set( 'isFontSubsettingEnabled', true );
            $options->set( 'isPhpEnabled', false );
            $options->set( 'chroot', KLEINBOOKS_PLUGIN_DIR );
            $dompdf = new \Dompdf\Dompdf($options);
            $dompdf->loadHtml( $html );
            $dompdf->setPaper( 'A4', 'portrait' );
            $dompdf->render();
        } catch ( \Exception $e ) {
            error_log( '[MK-PDF] Dompdf error: ' . $e->getMessage() );
            throw new Exception('PDF generation failed: ' . $e->getMessage());
        }
        // Get base PDF content from dompdf
        $pdf_content = $dompdf->output();
        $filename = $invoice['invoice_number'] . '.pdf';
        switch ( $output ) {
            case 'stream':
                // Display in browser
                header( 'Content-Type: application/pdf' );
                header( 'Content-Disposition: inline; filename="' . $filename . '"' );
                header( 'Content-Length: ' . strlen( $pdf_content ) );
                echo $pdf_content;
                exit;
            case 'download':
                // Force download
                header( 'Content-Type: application/pdf' );
                header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
                header( 'Content-Length: ' . strlen( $pdf_content ) );
                echo $pdf_content;
                exit;
            case 'string':
                // Return PDF content as string
                return $pdf_content;
            case 'save':
            default:
                // Save to file and return URL
                $upload_dir = wp_upload_dir();
                $year = $invoice['invoice_year'] ?? date( 'Y', strtotime( $invoice['date_issued'] ) );
                $pdf_dir = $upload_dir['basedir'] . '/mk-invoices/' . $year . '/';
                if ( !file_exists( $pdf_dir ) ) {
                    wp_mkdir_p( $pdf_dir );
                }
                $filepath = $pdf_dir . $filename;
                file_put_contents( $filepath, $pdf_content );
                $pdf_url = $upload_dir['baseurl'] . '/mk-invoices/' . $year . '/' . $filename;
                // Update invoice with PDF path
                $wpdb->update( $invoices_table, array(
                    'pdf_path' => $pdf_url,
                ), array(
                    'id' => $invoice_id,
                ) );
                return $pdf_url;
        }
    }

    /**
     * Render the invoice template
     */
    private static function render_template(
        $invoice,
        $client,
        $items,
        $settings
    ) {
        ob_start();
        // Brand logo as a base64 data-URI so DomPDF renders it without a remote fetch.
        // Both templates read $logo_data_uri (empty = today's text-only header/footer) and $logo_size.
        $logo_data_uri = self::get_logo_data_uri( $settings );
        $logo_size = $settings['logo_size'] ?? 'medium';
        // Client country for the address: German convention omits it for domestic
        // clients and shows it only for foreign ones. Uses the client's stored
        // country (templates previously hardcoded "DE").
        $client_country = trim( $client['country'] ?? '' );
        $client_country_label = ( $client_country === '' || in_array( mb_strtolower( $client_country ), array('deutschland', 'germany', 'de'), true ) ? '' : $client_country );
        // Choose template based on settings
        $template = $settings['invoice_template'] ?? 'classic';
        if ( $template === 'bold' ) {
            include KLEINBOOKS_PLUGIN_DIR . 'templates/invoice-pdf-bold.php';
        } else {
            include KLEINBOOKS_PLUGIN_DIR . 'templates/invoice-pdf.php';
        }
        return ob_get_clean();
    }

    /**
     * Generate an offer (Angebot) PDF. Mirrors generate() but for the offers tables and
     * offer templates. No ZUGFeRD embedding — an offer is not an e-invoice.
     */
    public static function generate_offer( $offer_id, $output = 'string' ) {
        global $wpdb;
        if ( !self::load_dompdf() ) {
            throw new Exception('Dompdf library not found');
        }
        $offers_table = KleinBooks_Database::get_table_name( 'offers' );
        $offer_items_table = KleinBooks_Database::get_table_name( 'offer_items' );
        $clients_table = KleinBooks_Database::get_table_name( 'clients' );
        $offer = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$offers_table} WHERE id = %d", $offer_id ), ARRAY_A );
        if ( !$offer ) {
            throw new Exception('Offer not found');
        }
        $client = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$clients_table} WHERE id = %d", $offer['client_id'] ), ARRAY_A );
        if ( !$client ) {
            throw new Exception('Client not found');
        }
        $items = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$offer_items_table} WHERE offer_id = %d ORDER BY sort_order, id", $offer_id ), ARRAY_A );
        $settings = KleinBooks_Database::get_all_settings();
        $html = self::render_offer_template(
            $offer,
            $client,
            $items,
            $settings
        );
        try {
            $options = new \Dompdf\Options();
            $options->set( 'isHtml5ParserEnabled', true );
            $options->set( 'isRemoteEnabled', false );
            $options->set( 'defaultFont', 'DejaVu Sans' );
            $options->set( 'isFontSubsettingEnabled', true );
            $options->set( 'isPhpEnabled', false );
            $options->set( 'chroot', KLEINBOOKS_PLUGIN_DIR );
            $dompdf = new \Dompdf\Dompdf($options);
            $dompdf->loadHtml( $html );
            $dompdf->setPaper( 'A4', 'portrait' );
            $dompdf->render();
        } catch ( \Exception $e ) {
            error_log( '[MK-PDF] Offer Dompdf error: ' . $e->getMessage() );
            throw new Exception('Offer PDF generation failed: ' . $e->getMessage());
        }
        $pdf_content = $dompdf->output();
        $filename = ($offer['offer_number'] ?? 'angebot') . '.pdf';
        switch ( $output ) {
            case 'stream':
                header( 'Content-Type: application/pdf' );
                header( 'Content-Disposition: inline; filename="' . $filename . '"' );
                header( 'Content-Length: ' . strlen( $pdf_content ) );
                echo $pdf_content;
                exit;
            case 'download':
                header( 'Content-Type: application/pdf' );
                header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
                header( 'Content-Length: ' . strlen( $pdf_content ) );
                echo $pdf_content;
                exit;
            case 'string':
            default:
                return $pdf_content;
        }
    }

    /**
     * Render the offer HTML from the offer templates (classic/bold by settings),
     * mirroring render_template() — same logo + country handling.
     */
    private static function render_offer_template(
        $offer,
        $client,
        $items,
        $settings
    ) {
        ob_start();
        $logo_data_uri = self::get_logo_data_uri( $settings );
        $logo_size = $settings['logo_size'] ?? 'medium';
        $client_country = trim( $client['country'] ?? '' );
        $client_country_label = ( $client_country === '' || in_array( mb_strtolower( $client_country ), array('deutschland', 'germany', 'de'), true ) ? '' : $client_country );
        $template = $settings['invoice_template'] ?? 'classic';
        if ( $template === 'bold' ) {
            include KLEINBOOKS_PLUGIN_DIR . 'templates/offer-pdf-bold.php';
        } else {
            include KLEINBOOKS_PLUGIN_DIR . 'templates/offer-pdf.php';
        }
        return ob_get_clean();
    }

    /**
     * Build a base64 data-URI for the company logo, or '' when none/unreadable.
     * PNG/JPG only (matches the upload route); reads the local uploads file so DomPDF
     * doesn't need remote fetching, and so it works inside the PDF/A-3 ZUGFeRD path.
     */
    private static function get_logo_data_uri( $settings ) {
        $url = $settings['logo_url'] ?? '';
        if ( empty( $url ) ) {
            return '';
        }
        $upload_dir = wp_upload_dir();
        $path = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $url );
        if ( !file_exists( $path ) ) {
            return '';
        }
        $ext = strtolower( pathinfo( $path, PATHINFO_EXTENSION ) );
        if ( $ext === 'png' ) {
            $mime = 'image/png';
        } elseif ( $ext === 'jpg' || $ext === 'jpeg' ) {
            $mime = 'image/jpeg';
        } else {
            return '';
        }
        $data = @file_get_contents( $path );
        if ( $data === false ) {
            return '';
        }
        return 'data:' . $mime . ';base64,' . base64_encode( $data );
    }

    /**
     * Get PDF URL for an invoice (generates if not exists)
     */
    public static function get_pdf_url( $invoice_id ) {
        global $wpdb;
        $invoices_table = KleinBooks_Database::get_table_name( 'invoices' );
        $invoice = $wpdb->get_row( $wpdb->prepare( "SELECT pdf_path, invoice_number, invoice_year, date_issued FROM {$invoices_table} WHERE id = %d", $invoice_id ), ARRAY_A );
        if ( !$invoice ) {
            return null;
        }
        // Check if PDF exists
        if ( !empty( $invoice['pdf_path'] ) ) {
            $upload_dir = wp_upload_dir();
            $year = $invoice['invoice_year'] ?? date( 'Y', strtotime( $invoice['date_issued'] ) );
            $filepath = $upload_dir['basedir'] . '/mk-invoices/' . $year . '/' . $invoice['invoice_number'] . '.pdf';
            if ( file_exists( $filepath ) ) {
                return $invoice['pdf_path'];
            }
        }
        // Generate new PDF
        return self::generate( $invoice_id, 'save' );
    }

    /**
     * Delete PDF file for an invoice
     */
    public static function delete_pdf( $invoice_id ) {
        global $wpdb;
        $invoices_table = KleinBooks_Database::get_table_name( 'invoices' );
        $invoice = $wpdb->get_row( $wpdb->prepare( "SELECT pdf_path, invoice_number, invoice_year, date_issued FROM {$invoices_table} WHERE id = %d", $invoice_id ), ARRAY_A );
        if ( $invoice && !empty( $invoice['pdf_path'] ) ) {
            $upload_dir = wp_upload_dir();
            $year = $invoice['invoice_year'] ?? date( 'Y', strtotime( $invoice['date_issued'] ) );
            $filepath = $upload_dir['basedir'] . '/mk-invoices/' . $year . '/' . $invoice['invoice_number'] . '.pdf';
            if ( file_exists( $filepath ) ) {
                unlink( $filepath );
            }
            // Clear pdf_path in database
            $wpdb->update( $invoices_table, array(
                'pdf_path' => '',
            ), array(
                'id' => $invoice_id,
            ) );
        }
    }

    /**
     * Regenerate PDF (delete old and create new)
     */
    public static function regenerate( $invoice_id ) {
        self::delete_pdf( $invoice_id );
        return self::generate( $invoice_id, 'save' );
    }

}
