<?php
/**
 * Freefactu Standalone PDF Generator
 *
 * Generates PDF invoices using DOMPDF.
 * This is the core PDF generation implementation of the Generator interface.
 *
 * @package Freefactu
 * @since 0.5.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

use Freefactu_Vendor\Dompdf\Dompdf;
use Freefactu_Vendor\Dompdf\Options;

/**
 * Class Freefactu_Standalone_Generator
 *
 * PDF generator implementation using DOMPDF library.
 * Renders invoice templates to HTML and converts to PDF using DOMPDF.
 *
 * @see Freefactu_Base_Generator For shared functionality
 */
class Freefactu_Standalone_Generator extends Freefactu_Base_Generator {

    /**
     * Reset state after order change.
     *
     * @return void
     */
    protected function reset_after_order_change() {
        // No additional state to reset in standalone mode
    }

    /**
     * Ensure environment is set.
     * Helper method to guarantee environment is available for operations.
     *
     * @return void
     */
    private function ensure_environment() {
        if ( ! $this->environment && class_exists( 'Freefactu_Factory' ) ) {
            $this->environment = Freefactu_Factory::create_environment();
        }
    }

    /**
     * Generate PDF for the order.
     *
     * @param WC_Order|int|null $order Optional order to generate PDF for.
     * @return string|WP_Error PDF content as string or WP_Error on failure.
     */
    public function generate( $order = null ) {
        // Set order if provided
        if ( $order !== null && ! $this->set_order( $order ) ) {
            return new WP_Error( 'invalid_order', __( 'Pedido no encontrado.', 'freefactu' ) );
        }

        if ( ! $this->order ) {
            return new WP_Error( 'no_order', __( 'No se ha especificado ningún pedido.', 'freefactu' ) );
        }

        // Try to get saved PDF first
        $saved_pdf = $this->get_saved_pdf( $this->order->get_id() );
        if ( $saved_pdf !== null ) {
            $this->pdf_content = $saved_pdf;
            return $this->pdf_content;
        }

        // Render HTML template
        $html = $this->render_template();
        if ( is_wp_error( $html ) ) {
            return $html;
        }

        // Generate PDF from HTML
        $this->pdf_content = $this->generate_pdf_from_html( $html );
        
        if ( is_wp_error( $this->pdf_content ) ) {
            return $this->pdf_content;
        }

        // Save PDF if it was missing
        $this->save_pdf_if_missing( $this->order->get_id(), $this->pdf_content );

        return $this->pdf_content;
    }

    /**
     * Render the invoice template to HTML.
     *
     * @param WC_Order|int|null $order Optional order to render template for.
     * @return string|WP_Error HTML content or WP_Error on failure.
     */
    public function render_template( $order = null ) {
        // Set order if provided
        if ( $order !== null && ! $this->set_order( $order ) ) {
            return new WP_Error( 'invalid_order', __( 'Pedido no encontrado.', 'freefactu' ) );
        }

        if ( ! $this->order ) {
            return new WP_Error( 'no_order', __( 'No se ha especificado ningún pedido.', 'freefactu' ) );
        }

        // Get template path
        $template_path = $this->get_template_path();

        if ( ! Freefactu_Filesystem::exists( $template_path ) ) {
            return new WP_Error(
                'template_not_found',
                __( 'Plantilla de factura no encontrada.', 'freefactu' )
            );
        }

        // Prepare template data
        $data = $this->prepare_template_data();

        // Render template
        ob_start();
        include $template_path;
        $html = ob_get_clean();

        return $html;
    }

    /**
     * Get the path to the invoice template.
     *
     * @return string Template file path.
     */
    private function get_template_path() {
        // Allow theme/child theme override
        $theme_template = get_stylesheet_directory() . '/freefactu/invoice.php';
        if ( Freefactu_Filesystem::exists( $theme_template ) ) {
            return $theme_template;
        }

        // Default plugin template
        return FREEFACTU_PLUGIN_DIR . 'templates/invoice.php';
    }



    /**
     * Get filename for PDF (overrides base method to handle deleted orders).
     *
     * @param int|null $order_id Optional order ID for deleted orders.
     * @return string Filename.
     */
    protected function get_filename( $order_id = null ) {
        // If order exists, use parent method
        if ( $this->order ) {
            return parent::get_filename();
        }

        // Order is deleted - use order_id parameter or try to get from invoice
        if ( ! $order_id ) {
            // Try to extract order_id from context if available
            // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            $order_id = isset( $_GET['order_id'] ) ? absint( $_GET['order_id'] ) : 0;
        }

        if ( $order_id ) {
            // Get invoice number from database
            $invoice_db = Freefactu_DB::get_invoice_by_order_id( $order_id );
            $invoice_number = $invoice_db ? $invoice_db->invoice_number : '';

            if ( empty( $invoice_number ) ) {
                $invoice_number = $order_id;
            }

            // Sanitize for filename
            $safe_number = str_replace( array( '/', '\\', ' ' ), '-', $invoice_number );

            return 'verifactu-' . $safe_number . '.pdf';
        }

        // Fallback
        return 'verifactu-invoice.pdf';
    }

    /**
     * Output PDF to browser.
     *
     * @param string $mode Output mode: 'inline' for browser view, 'download' for file download.
     * @return void|WP_Error
     */
    public function output_pdf( string $mode = 'inline' ) {
        // Generate PDF if not already generated
        if ( $this->pdf_content === null ) {
            $result = $this->generate();
            if ( is_wp_error( $result ) ) {
                return $result;
            }
        }

        if ( empty( $this->pdf_content ) ) {
            return new WP_Error( 'empty_pdf', __( 'No se pudo generar el PDF.', 'freefactu' ) );
        }

        // Clean output buffer
        if ( ob_get_length() ) {
            ob_end_clean();
        }

        // Get filename (handles both existing and deleted orders)
        $filename = $this->get_filename( isset( $this->order ) ? $this->order->get_id() : ( isset( $_GET['order_id'] ) ? absint( $_GET['order_id'] ) : 0 ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended

        // Set headers
        header( 'Content-Type: application/pdf' );
        header( 'Content-Length: ' . strlen( $this->pdf_content ) );

        if ( $mode === 'download' ) {
            header( 'Content-Disposition: attachment; filename="' . sanitize_file_name( $filename ) . '"' );
        } else {
            header( 'Content-Disposition: inline; filename="' . sanitize_file_name( $filename ) . '"' );
        }

        header( 'Cache-Control: private, max-age=0, must-revalidate' );
        header( 'Pragma: public' );


        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        echo $this->pdf_content;
        exit;
    }

    /**
     * Generate PDF from HTML content using DOMPDF.
     *
     * @param string $html HTML content.
     * @return string|WP_Error PDF content or WP_Error on failure.
     */
    protected function generate_pdf_from_html( $html ) {
        // Check if DOMPDF is available
        if ( ! class_exists( 'Freefactu_Vendor\\Dompdf\\Dompdf' ) ) {
            return new WP_Error(
                'dompdf_not_found',
                __( 'DOMPDF no está disponible. Por favor, ejecute "composer install" en el directorio del plugin.', 'freefactu' )
            );
        }

        try {
            // Configure DOMPDF options
            $options = new Options();
            $options->set( 'isRemoteEnabled', true );
            $options->set( 'isHtml5ParserEnabled', true );
            $options->set( 'defaultFont', 'DejaVu Sans' );
            $options->set( 'tempDir', sys_get_temp_dir() );

            // Create DOMPDF instance
            $dompdf = new Dompdf( $options );
            $dompdf->loadHtml( $html );
            $dompdf->setPaper( 'A4', 'portrait' );
            $dompdf->render();

            // Get PDF content
            return $dompdf->output();

        } catch ( Exception $e ) {
            Freefactu_Logger::log( 'PDF Generation Error: ' . $e->getMessage(), 'error' );
            return new WP_Error( 'pdf_generation_failed', $e->getMessage() );
        }
    }

    /**
     * Get the URL for viewing the PDF in the browser.
     *
     * @param int $order_id Order ID.
     * @return string PDF view URL.
     */
    public function get_pdf_url( int $order_id ): string {
        return wp_nonce_url(
            admin_url( 'admin-post.php?action=freefactu_standalone_pdf&order_id=' . $order_id . '&output=inline' ),
            'freefactu_standalone_pdf_' . $order_id
        );
    }

    /**
     * Register hooks for handling PDF output requests.
     *
     * @return void
     */
    public function register_output_hooks() {
        add_action( 'admin_post_freefactu_standalone_pdf', array( $this, 'handle_pdf_output_request' ) );
    }

    /**
     * Handle PDF output request from admin-post.php.
     *
     * @return void
     */
    public function handle_pdf_output_request() {

        // Verify capability
        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_die( esc_html__( 'No tienes permisos para ver esta factura.', 'freefactu' ) );
        }

        // Get order ID
        $order_id = isset( $_GET['order_id'] ) ? absint( $_GET['order_id'] ) : 0;

        if ( ! $order_id ) {
            wp_die( esc_html__( 'ID de pedido inválido.', 'freefactu' ) );
        }

        // Verify nonce
        $nonce = isset( $_GET['_wpnonce'] ) ? sanitize_key( wp_unslash( $_GET['_wpnonce'] ) ) : '';
        if ( ! wp_verify_nonce( $nonce, 'freefactu_standalone_pdf_' . $order_id ) ) {
            wp_die( esc_html__( 'Enlace de seguridad inválido.', 'freefactu' ) );
        }

        // Get output mode (sanitized to only allow 'download' or default to 'inline')
        $output_mode = isset( $_GET['output'] ) && sanitize_key( wp_unslash( $_GET['output'] ) ) === 'download' ? 'download' : 'inline';

        // Try to set order - if it fails, check if we have snapshot data
        if ( ! $this->set_order( $order_id ) ) {
            // Order not found - try to use snapshot data from database
            try {
                Freefactu_Logger::log( sprintf( 'Order %d not found, attempting to use snapshot data', $order_id ), 'info' );
                
                $invoice = Freefactu_DB::get_invoice_by_order_id( $order_id );
                
                if ( ! $invoice ) {
                    Freefactu_Logger::log( sprintf( 'No invoice found for order %d', $order_id ), 'error' );
                    wp_die( esc_html__( 'Pedido no encontrado y no hay datos de factura guardados.', 'freefactu' ) );
                }
                
                if ( empty( $invoice->invoice_snapshot ) ) {
                    Freefactu_Logger::log( sprintf( 'Invoice found but snapshot is empty for order %d', $order_id ), 'error' );
                    wp_die( esc_html__( 'No hay datos de factura guardados para este pedido.', 'freefactu' ) );
                }

                // Decode snapshot data
                $snapshot = json_decode( $invoice->invoice_snapshot, true );
                
                if ( empty( $snapshot ) || ! is_array( $snapshot ) ) {
                    Freefactu_Logger::log( sprintf( 'Invalid snapshot data for order %d: %s', $order_id, substr( $invoice->invoice_snapshot, 0, 100 ) ), 'error' );
                    wp_die( esc_html__( 'Los datos de factura guardados no son válidos.', 'freefactu' ) );
                }

                Freefactu_Logger::log( sprintf( 'Snapshot data loaded successfully for order %d', $order_id ), 'info' );

                // Ensure environment is set for QR generation
                $this->ensure_environment();
                if ( ! $this->environment ) {
                    Freefactu_Logger::log( 'Failed to create environment instance', 'error' );
                    wp_die( esc_html__( 'Error: No se pudo inicializar el sistema de generación de PDF.', 'freefactu' ) );
                }

                // Generate PDF from snapshot
                Freefactu_Logger::log( sprintf( 'Generating PDF from snapshot for order %d', $order_id ), 'info' );
                $pdf_result = $this->generate_from_snapshot( $order_id, $snapshot );
                
                if ( is_wp_error( $pdf_result ) ) {
                    Freefactu_Logger::log( sprintf( 'PDF generation from snapshot failed for order %d: %s', $order_id, $pdf_result->get_error_message() ), 'error' );
                    wp_die( esc_html( $pdf_result->get_error_message() ) );
                }

                Freefactu_Logger::log( sprintf( 'PDF generated successfully from snapshot for order %d', $order_id ), 'info' );

                // Set the PDF content for output
                $this->pdf_content = $pdf_result;
                
            } catch ( \Throwable $e ) {
                Freefactu_Logger::log( sprintf( 'Fatal error generating PDF from snapshot for order %d: %s in %s:%d', $order_id, $e->getMessage(), $e->getFile(), $e->getLine() ), 'error' );
                Freefactu_Logger::log( 'Stack trace: ' . $e->getTraceAsString(), 'error' );
                /* translators: %s: Error message */
                wp_die( sprintf( esc_html__( 'Error crítico al generar PDF: %s', 'freefactu' ), esc_html( $e->getMessage() ) ) );
            }
        }

        $result = $this->output_pdf( $output_mode );

        if ( is_wp_error( $result ) ) {
            wp_die( esc_html( $result->get_error_message() ) );
        }
    }
}
