<?php
/**
 * WooCommerce order hooks: auto-generation, meta box, admin column, email attachment.
 *
 * @package FacturX_For_WooCommerce
 */

defined( 'ABSPATH' ) || exit;

class GOFACTOX_Order_Hooks {

    public static function init(): void {
        // Auto-generate invoice on status change.
        add_action( 'woocommerce_order_status_changed', [ __CLASS__, 'maybe_auto_generate' ], 10, 3 );

        // Auto-generate credit note on refund creation (Pro feature).
        add_action( 'woocommerce_refund_created', [ __CLASS__, 'maybe_auto_generate_credit_note' ], 10, 2 );

        // Meta box on order edit page.
        add_action( 'add_meta_boxes', [ __CLASS__, 'add_meta_box' ] );

        // Admin column in orders list.
        add_filter( 'manage_woocommerce_page_wc-orders_columns', [ __CLASS__, 'add_order_column' ] );
        add_action( 'manage_woocommerce_page_wc-orders_custom_column', [ __CLASS__, 'render_order_column' ], 10, 2 );

        // Legacy CPT-based orders (if HPOS is disabled).
        add_filter( 'manage_edit-shop_order_columns', [ __CLASS__, 'add_order_column' ] );
        add_action( 'manage_shop_order_posts_custom_column', [ __CLASS__, 'render_order_column_legacy' ], 10, 2 );

        // Email attachment.
        add_filter( 'woocommerce_email_attachments', [ __CLASS__, 'attach_to_email' ], 10, 4 );

        // AJAX handlers for manual generation.
        add_action( 'wp_ajax_gofactox_generate_invoice', [ __CLASS__, 'ajax_generate_invoice' ] );
        add_action( 'wp_ajax_gofactox_generate_credit_note', [ __CLASS__, 'ajax_generate_credit_note' ] );
    }

    /**
     * Auto-generate a credit note when a WooCommerce refund is created.
     *
     * Mirrors the auto-generate-invoice flow but gated on:
     * - Pro license (auto-generation is a Pro feature)
     * - Setting gofactox_auto_generate_credit_notes (default yes)
     * - The parent order already has an invoice (legal prerequisite)
     */
    public static function maybe_auto_generate_credit_note( int $refund_id, array $args = [] ): void {
        if ( ! GOFACTOX_License::is_pro() ) {
            return;
        }

        if ( get_option( 'gofactox_auto_generate_credit_notes', 'yes' ) !== 'yes' ) {
            return;
        }

        $refund = wc_get_order( $refund_id );
        if ( ! $refund instanceof \WC_Order_Refund ) {
            return;
        }

        // Skip if a credit note has already been generated for this refund.
        if ( $refund->get_meta( '_gofactox_credit_note_id' ) ) {
            return;
        }

        // Parent order must have an invoice; otherwise the credit note has nothing to reference.
        $parent_order = wc_get_order( $refund->get_parent_id() );
        if ( ! $parent_order instanceof \WC_Order || ! $parent_order->get_meta( '_gofactox_invoice_id' ) ) {
            if ( function_exists( 'wc_get_logger' ) ) {
                wc_get_logger()->warning(
                    sprintf( 'Skipping credit note auto-generation for refund #%d: parent order has no invoice.', $refund_id ),
                    [ 'source' => 'gofactox-e-invoicing-for-woocommerce' ]
                );
            }
            return;
        }

        self::generate_credit_note_for_refund( $refund );
    }

    /**
     * Generate a credit note for a refund. Returns the PDF path or false on failure.
     *
     * Fires `gofactox_credit_note_created` action on first generation, and
     * `gofactox_credit_note_regenerated` when an existing credit note is replaced.
     */
    public static function generate_credit_note_for_refund( \WC_Order_Refund $refund ): string|false {
        self::$last_error = '';

        // Credit notes are a Pro feature: industry standard (WPOvernight, WebToffee,
        // Flexible Invoices, Bas Elbers all gate avoirs behind a paid plan).
        if ( ! GOFACTOX_License::is_pro() ) {
            self::$last_error = __( 'Credit notes are a Pro feature. Upgrade to GoFactoX Pro to enable refund-to-credit-note generation.', 'gofactox-e-invoicing-for-woocommerce' );
            return false;
        }

        $was_existing = (bool) $refund->get_meta( '_gofactox_credit_note_id' );
        try {
            $cn_id = GOFACTOX_Invoice::create_for_refund( $refund );
            if ( ! $cn_id ) {
                self::$last_error = __( 'Cannot create credit note: parent order must have an invoice first.', 'gofactox-e-invoicing-for-woocommerce' );
                return false;
            }

            $data = GOFACTOX_Invoice::get_credit_note_data( $refund );
            $path = GOFACTOX_FacturX_Merger::generate_invoice( $data, $refund );

            // PDP transmission for credit notes will be wired once the official AIFE
            // APIs accept type-381 documents; the current connector signature is
            // typed for WC_Order only and skipping is the safe default for now.

            // Webhook-friendly action hooks.
            $hook = $was_existing ? 'gofactox_credit_note_regenerated' : 'gofactox_credit_note_created';
            do_action( $hook, $cn_id, $refund, $path );

            return $path;
        } catch ( \Throwable $e ) {
            self::$last_error = $e->getMessage();
            if ( function_exists( 'wc_get_logger' ) ) {
                wc_get_logger()->error( 'Credit note generation failed for refund #' . $refund->get_id() . ': ' . $e->getMessage(), [ 'source' => 'gofactox-e-invoicing-for-woocommerce' ] );
            }
            return false;
        }
    }

    /**
     * Auto-generate invoice when order reaches the configured status.
     */
    public static function maybe_auto_generate( int $order_id, string $old_status, string $new_status ): void {
        // Auto-generation is a Pro feature.
        if ( ! GOFACTOX_License::is_pro() ) {
            return;
        }

        if ( get_option( 'gofactox_auto_generate', 'yes' ) !== 'yes' ) {
            return;
        }

        $trigger = get_option( 'gofactox_auto_generate_status', 'completed' );
        if ( $new_status !== $trigger ) {
            return;
        }

        $order = wc_get_order( $order_id );
        if ( ! $order ) {
            return;
        }

        // Skip if invoice already exists.
        if ( $order->get_meta( '_gofactox_invoice_id' ) ) {
            return;
        }

        self::generate_invoice_for_order( $order );
    }

    /**
     * Generate a complete invoice for an order.
     *
     * Fires `gofactox_invoice_created` action on first generation, and
     * `gofactox_invoice_regenerated` when an existing invoice is replaced.
     *
     * @return string|false Path to the generated PDF/A-3 on success, false on failure.
     *                     On failure, the last error message is available via get_last_error().
     */
    public static function generate_invoice_for_order( \WC_Order $order ): string|false {
        self::$last_error = '';
        $was_existing = (bool) $order->get_meta( '_gofactox_invoice_id' );
        try {
            // Create invoice record.
            $invoice_id = GOFACTOX_Invoice::create_for_order( $order );
            if ( ! $invoice_id ) {
                self::$last_error = __( 'Could not create the invoice record. Try again or check the WooCommerce logs.', 'gofactox-e-invoicing-for-woocommerce' );
                return false;
            }

            // Get invoice data.
            $data = GOFACTOX_Invoice::get_invoice_data( $order );

            // Generate PDF/A-3 (or XML-only for CII/UBL).
            $path = GOFACTOX_FacturX_Merger::generate_invoice( $data, $order );

            // Auto-transmit to PDP if configured.
            if ( GOFACTOX_PDP_Manager::is_available() ) {
                GOFACTOX_PDP_Manager::queue_transmission( $order );
            }

            // Webhook-friendly action hooks. Listeners can pull data via the order or
            // invoice ID, or use the WooCommerce REST webhook system which subscribes
            // to these hooks via topics declared in class-gofactox-rest-api.php.
            $hook = $was_existing ? 'gofactox_invoice_regenerated' : 'gofactox_invoice_created';
            do_action( $hook, $invoice_id, $order, $path );

            return $path;
        } catch ( \Throwable $e ) {
            self::$last_error = $e->getMessage();
            // Log error but don't break the order flow.
            if ( function_exists( 'wc_get_logger' ) ) {
                wc_get_logger()->error( 'Invoice generation failed for order #' . $order->get_id() . ': ' . $e->getMessage(), [ 'source' => 'gofactox-e-invoicing-for-woocommerce' ] );
            }
            return false;
        }
    }

    /** @var string Last error message from generate_invoice_for_order(). */
    private static string $last_error = '';

    public static function get_last_error(): string {
        return self::$last_error;
    }

    /**
     * Add meta box to order edit page.
     */
    public static function add_meta_box(): void {
        $screen = function_exists( 'wc_get_page_screen_id' ) ? wc_get_page_screen_id( 'shop-order' ) : 'shop_order';

        add_meta_box(
            'gofactox-invoice-meta-box',
            __( 'Factur-X Invoice', 'gofactox-e-invoicing-for-woocommerce' ),
            [ __CLASS__, 'render_meta_box' ],
            $screen,
            'side',
            'high'
        );

        // Legacy fallback for non-HPOS stores.
        if ( $screen !== 'shop_order' ) {
            add_meta_box(
                'gofactox-invoice-meta-box',
                __( 'Factur-X Invoice', 'gofactox-e-invoicing-for-woocommerce' ),
                [ __CLASS__, 'render_meta_box' ],
                'shop_order',
                'side',
                'high'
            );
        }
    }

    /**
     * Render the meta box content.
     */
    public static function render_meta_box( $post_or_order ): void {
        $order = $post_or_order instanceof \WC_Order
            ? $post_or_order
            : wc_get_order( $post_or_order->ID );

        if ( ! $order ) {
            return;
        }

        $invoice_number = $order->get_meta( '_gofactox_invoice_number' );
        $invoice_id     = $order->get_meta( '_gofactox_invoice_id' );

        // Persistent error placeholder for AJAX feedback.
        echo '<div class="gofactox-error-panel" style="display:none;margin-bottom:10px;padding:8px 10px;background:#fcf0f1;border-left:4px solid #d63638;color:#1d2327;font-size:13px;line-height:1.5;"></div>';

        // Surface incomplete company configuration before any generation attempt.
        $config_errors = GOFACTOX_Invoice::get_validation_errors();
        if ( ! empty( $config_errors ) ) {
            self::render_config_warning( $config_errors );
        }

        $nonce = wp_create_nonce( 'gofactox_generate_invoice' );

        if ( $invoice_number && $invoice_id ) {
            $pdf_path = GOFACTOX_Invoice::get_pdf_path( (int) $invoice_id );
            $has_pdf  = $pdf_path && file_exists( $pdf_path );

            echo '<div style="margin-bottom: 8px;">';
            echo '<strong>' . esc_html__( 'Invoice:', 'gofactox-e-invoicing-for-woocommerce' ) . '</strong> ';
            echo esc_html( $invoice_number );
            echo '</div>';

            if ( $has_pdf ) {
                $download_url = GOFACTOX_Download::get_download_url( $order );
                echo '<a href="' . esc_url( $download_url ) . '" class="button" target="_blank">';
                echo esc_html__( 'Download PDF', 'gofactox-e-invoicing-for-woocommerce' );
                echo '</a>';
            }

            $regen_disabled = ! empty( $config_errors ) ? ' disabled aria-disabled="true"' : '';
            echo ' <a href="#" class="button gofactox-regenerate"' . esc_attr( $regen_disabled ) . ' data-order-id="' . esc_attr( $order->get_id() ) . '" data-nonce="' . esc_attr( $nonce ) . '">';
            echo esc_html__( 'Regenerate', 'gofactox-e-invoicing-for-woocommerce' );
            echo '</a>';
        } else {
            echo '<p>' . esc_html__( 'No invoice generated yet.', 'gofactox-e-invoicing-for-woocommerce' ) . '</p>';
            $btn_disabled = ! empty( $config_errors ) ? ' disabled aria-disabled="true"' : '';
            echo '<a href="#" class="button button-primary gofactox-generate"' . esc_attr( $btn_disabled ) . ' data-order-id="' . esc_attr( $order->get_id() ) . '" data-nonce="' . esc_attr( $nonce ) . '">';
            echo esc_html__( 'Generate Invoice', 'gofactox-e-invoicing-for-woocommerce' );
            echo '</a>';
        }

        // Credit notes section: one block per refund on the order (Pro feature).
        if ( GOFACTOX_License::is_pro() ) {
            self::render_credit_notes_section( $order, $config_errors, $nonce );
        } elseif ( ! empty( $order->get_refunds() ) ) {
            // Refunds exist but the merchant doesn't have Pro: show an upsell stub.
            echo '<hr style="margin:12px 0 8px;">';
            echo '<div style="margin-bottom:6px;font-weight:600;">' . esc_html__( 'Credit Notes', 'gofactox-e-invoicing-for-woocommerce' ) . '</div>';
            echo '<p style="margin:0;font-size:12px;color:#646970;">' . esc_html__( 'Generating Factur-X credit notes (type 381) on refunds requires the Pro plan.', 'gofactox-e-invoicing-for-woocommerce' ) . '</p>';
        }

        // Inline JS: AJAX call + structured error rendering (no native alert).
        $messages = [
            'generating' => __( 'Generating...', 'gofactox-e-invoicing-for-woocommerce' ),
            'retry'      => __( 'Retry', 'gofactox-e-invoicing-for-woocommerce' ),
            'fallback'   => __( 'Invoice generation failed. Please retry, or check WooCommerce > Status > Logs.', 'gofactox-e-invoicing-for-woocommerce' ),
            'missing'    => __( 'Missing required company fields:', 'gofactox-e-invoicing-for-woocommerce' ),
            'configure'  => __( 'Open Factur-X settings', 'gofactox-e-invoicing-for-woocommerce' ),
        ];

        $script = "jQuery(function(\$){
            var msgs = " . wp_json_encode( $messages ) . ";
            var \$panel = \$('.gofactox-error-panel');
            function showError(data){
                var html = '';
                if (data && data.missing_fields && data.missing_fields.length){
                    html += '<strong>' + msgs.missing + '</strong><ul style=\"margin:4px 0 6px 18px;\">';
                    data.missing_fields.forEach(function(f){ html += '<li>' + \$('<div>').text(f).html() + '</li>'; });
                    html += '</ul>';
                }
                var message = (data && data.message) ? data.message : ((typeof data === 'string') ? data : msgs.fallback);
                html += '<div>' + \$('<div>').text(message).html() + '</div>';
                if (data && data.settings_url){
                    html += '<a class=\"button button-small\" style=\"margin-top:6px;\" href=\"' + data.settings_url + '\">' + msgs.configure + '</a>';
                }
                \$panel.html(html).show();
            }
            function runAction(\$b, payload){
                if (\$b.is('[disabled]') || \$b.attr('aria-disabled') === 'true'){ return; }
                \$panel.hide().empty();
                \$b.attr('aria-disabled', 'true').addClass('disabled').text(msgs.generating);
                \$.post(ajaxurl, payload).done(function(r){
                    if (r && r.success){
                        location.reload();
                        return;
                    }
                    showError(r ? r.data : null);
                    \$b.attr('aria-disabled', 'false').removeClass('disabled').text(msgs.retry);
                }).fail(function(xhr){
                    var data = null;
                    if (xhr && xhr.responseJSON && xhr.responseJSON.data){ data = xhr.responseJSON.data; }
                    showError(data || (msgs.fallback + ' (HTTP ' + (xhr ? xhr.status : '?') + ')'));
                    \$b.attr('aria-disabled', 'false').removeClass('disabled').text(msgs.retry);
                });
            }
            \$(document).on('click', '.gofactox-generate, .gofactox-regenerate', function(e){
                e.preventDefault();
                var \$b = \$(this);
                runAction(\$b, {action:'gofactox_generate_invoice', order_id:\$b.data('order-id'), _wpnonce:\$b.data('nonce')});
            });
            \$(document).on('click', '.gofactox-cn-generate, .gofactox-cn-regenerate', function(e){
                e.preventDefault();
                var \$b = \$(this);
                runAction(\$b, {action:'gofactox_generate_credit_note', refund_id:\$b.data('refund-id'), _wpnonce:\$b.data('nonce')});
            });
        });";
        // Print the script inline in the meta box: wp_add_inline_script('jquery', ...) is
        // a no-op here because jquery is already printed by the time the meta box renders
        // on the HPOS order edit screen, leaving the click handler unbound.
        // The $script content is assembled from translated strings (run through wp_json_encode)
        // and static templated code we fully control; it never contains user input.
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        echo "<script type=\"text/javascript\">/* <![CDATA[ */\n" . $script . "\n/* ]]> */</script>";
    }

    /**
     * Render the credit notes block: one row per refund attached to the order.
     *
     * @param array<string, string> $config_errors Seller validation errors, used to disable buttons.
     * @param string                $nonce         Pre-generated AJAX nonce.
     */
    private static function render_credit_notes_section( \WC_Order $order, array $config_errors, string $nonce ): void {
        $refunds = $order->get_refunds();
        if ( empty( $refunds ) ) {
            return;
        }

        $has_invoice = (bool) $order->get_meta( '_gofactox_invoice_id' );

        echo '<hr style="margin:12px 0 8px;">';
        echo '<div style="margin-bottom:6px;font-weight:600;">' . esc_html__( 'Credit Notes', 'gofactox-e-invoicing-for-woocommerce' ) . '</div>';

        if ( ! $has_invoice ) {
            echo '<p style="margin:0 0 6px;font-size:12px;color:#646970;">' . esc_html__( 'Generate the invoice first; credit notes must reference an existing invoice.', 'gofactox-e-invoicing-for-woocommerce' ) . '</p>';
        }

        foreach ( $refunds as $refund ) {
            if ( ! $refund instanceof \WC_Order_Refund ) {
                continue;
            }

            $cn_id      = (int) $refund->get_meta( '_gofactox_credit_note_id' );
            $cn_number  = (string) $refund->get_meta( '_gofactox_credit_note_number' );
            $amount     = abs( (float) $refund->get_total() );
            $currency   = $order->get_currency();
            $btn_lock   = ( ! $has_invoice || ! empty( $config_errors ) ) ? ' aria-disabled="true" disabled' : '';

            echo '<div style="margin-bottom:8px;padding:6px 8px;background:#f6f7f7;border-radius:3px;">';
            echo '<div style="font-size:12px;color:#1d2327;">';
            echo '<strong>' . esc_html( sprintf(
                /* translators: 1: refund id, 2: refund amount formatted */
                __( 'Refund #%1$d (-%2$s %3$s)', 'gofactox-e-invoicing-for-woocommerce' ),
                $refund->get_id(),
                number_format( $amount, 2, ',', ' ' ),
                $currency
            ) ) . '</strong>';
            echo '</div>';

            if ( $cn_id && $cn_number ) {
                $pdf_path = GOFACTOX_Invoice::get_pdf_path( $cn_id );
                $has_pdf  = $pdf_path && file_exists( $pdf_path );

                echo '<div style="margin:4px 0;font-size:12px;">' . esc_html( $cn_number ) . '</div>';
                if ( $has_pdf ) {
                    echo '<a href="' . esc_url( GOFACTOX_Download::get_credit_note_download_url( $refund ) ) . '" class="button button-small" target="_blank">';
                    echo esc_html__( 'Download PDF', 'gofactox-e-invoicing-for-woocommerce' );
                    echo '</a> ';
                }
                echo '<a href="#" class="button button-small gofactox-cn-regenerate"' . esc_attr( $btn_lock ) . ' data-refund-id="' . esc_attr( $refund->get_id() ) . '" data-nonce="' . esc_attr( $nonce ) . '">';
                echo esc_html__( 'Regenerate', 'gofactox-e-invoicing-for-woocommerce' );
                echo '</a>';
            } else {
                echo '<div style="margin:4px 0;font-size:12px;color:#646970;">' . esc_html__( 'No credit note yet.', 'gofactox-e-invoicing-for-woocommerce' ) . '</div>';
                echo '<a href="#" class="button button-small button-primary gofactox-cn-generate"' . esc_attr( $btn_lock ) . ' data-refund-id="' . esc_attr( $refund->get_id() ) . '" data-nonce="' . esc_attr( $nonce ) . '">';
                echo esc_html__( 'Generate Credit Note', 'gofactox-e-invoicing-for-woocommerce' );
                echo '</a>';
            }
            echo '</div>';
        }
    }

    /**
     * Render the warning panel listing missing seller config fields.
     *
     * @param array<string, string> $config_errors Map of slug => label.
     */
    private static function render_config_warning( array $config_errors ): void {
        $settings_url = GOFACTOX_Invoice::get_settings_url();
        echo '<div style="margin-bottom:10px;padding:8px 10px;background:#fcf9e8;border-left:4px solid #dba617;color:#1d2327;font-size:13px;line-height:1.5;">';
        echo '<strong>' . esc_html__( 'Cannot generate invoice: company information incomplete.', 'gofactox-e-invoicing-for-woocommerce' ) . '</strong>';
        echo '<ul style="margin:4px 0 6px 18px;list-style:disc;">';
        foreach ( $config_errors as $label ) {
            echo '<li>' . esc_html( $label ) . '</li>';
        }
        echo '</ul>';
        echo '<a class="button button-small" href="' . esc_url( $settings_url ) . '">' . esc_html__( 'Open Factur-X settings', 'gofactox-e-invoicing-for-woocommerce' ) . '</a>';
        echo '</div>';
    }

    /**
     * Add "Invoice" column to orders list.
     */
    public static function add_order_column( array $columns ): array {
        $new = [];
        foreach ( $columns as $key => $label ) {
            $new[ $key ] = $label;
            if ( $key === 'order_total' ) {
                $new['gofactox_invoice'] = __( 'Invoice', 'gofactox-e-invoicing-for-woocommerce' );
            }
        }
        return $new;
    }

    /**
     * Render the invoice column (HPOS).
     */
    public static function render_order_column( string $column, $order ): void {
        if ( $column !== 'gofactox_invoice' ) {
            return;
        }

        if ( ! $order instanceof \WC_Order ) {
            $order = wc_get_order( $order );
        }

        if ( ! $order ) {
            return;
        }

        $invoice_number = $order->get_meta( '_gofactox_invoice_number' );
        if ( $invoice_number ) {
            $download_url = GOFACTOX_Download::get_download_url( $order );
            echo '<a href="' . esc_url( $download_url ) . '" title="' . esc_attr__( 'Download Invoice', 'gofactox-e-invoicing-for-woocommerce' ) . '">';
            echo esc_html( $invoice_number );
            echo '</a>';
        } else {
            echo '-';
        }
    }

    /**
     * Render the invoice column (legacy CPT).
     */
    public static function render_order_column_legacy( string $column, int $post_id ): void {
        if ( $column !== 'gofactox_invoice' ) {
            return;
        }

        $order = wc_get_order( $post_id );
        if ( $order ) {
            self::render_order_column( $column, $order );
        }
    }

    /**
     * Attach invoice PDF to order emails.
     */
    public static function attach_to_email( array $attachments, string $email_id, $order, $email = null ): array {
        // Email attachment is a Pro feature.
        if ( ! GOFACTOX_License::is_pro() ) {
            return $attachments;
        }

        if ( get_option( 'gofactox_attach_to_email', 'yes' ) !== 'yes' ) {
            return $attachments;
        }

        // Only attach to specific email types.
        $allowed_emails = [ 'customer_completed_order', 'customer_processing_order', 'customer_invoice' ];
        if ( ! in_array( $email_id, $allowed_emails, true ) ) {
            return $attachments;
        }

        if ( ! $order instanceof \WC_Order ) {
            return $attachments;
        }

        $invoice_id = $order->get_meta( '_gofactox_invoice_id' );
        if ( ! $invoice_id ) {
            return $attachments;
        }

        $pdf_path = GOFACTOX_Invoice::get_pdf_path( (int) $invoice_id );
        if ( $pdf_path && file_exists( $pdf_path ) ) {
            $attachments[] = $pdf_path;
        }

        return $attachments;
    }

    /**
     * AJAX handler for manual invoice generation.
     */
    public static function ajax_generate_invoice(): void {
        check_ajax_referer( 'gofactox_generate_invoice' );

        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( [
                'message' => __( 'You do not have permission to generate invoices.', 'gofactox-e-invoicing-for-woocommerce' ),
            ] );
        }

        $order_id = isset( $_POST['order_id'] ) ? (int) sanitize_text_field( wp_unslash( $_POST['order_id'] ) ) : 0;
        $order    = wc_get_order( $order_id );

        if ( ! $order ) {
            wp_send_json_error( [
                'message' => __( 'Order not found.', 'gofactox-e-invoicing-for-woocommerce' ),
            ] );
        }

        // Pre-flight: company configuration must be complete.
        $config_errors = GOFACTOX_Invoice::get_validation_errors();
        if ( ! empty( $config_errors ) ) {
            wp_send_json_error( [
                'message'        => __( 'Company information is incomplete. Fill the missing fields before generating an invoice.', 'gofactox-e-invoicing-for-woocommerce' ),
                'missing_fields' => array_values( $config_errors ),
                'settings_url'   => GOFACTOX_Invoice::get_settings_url(),
            ] );
        }

        // For regeneration, delete existing invoice data.
        $existing_id = $order->get_meta( '_gofactox_invoice_id' );
        if ( $existing_id ) {
            $old_path = GOFACTOX_Invoice::get_pdf_path( (int) $existing_id );
            if ( $old_path && file_exists( $old_path ) ) {
                wp_delete_file( $old_path );
            }
            wp_delete_post( (int) $existing_id, true );
            $order->delete_meta_data( '_gofactox_invoice_id' );
            $order->delete_meta_data( '_gofactox_invoice_number' );
            $order->save();
        }

        $result = self::generate_invoice_for_order( $order );

        if ( $result ) {
            wp_send_json_success( [ 'path' => $result ] );
        }

        $detail = self::get_last_error();
        $message = $detail
            ? sprintf(
                /* translators: %s: detailed error message from the generator */
                __( 'Invoice generation failed: %s', 'gofactox-e-invoicing-for-woocommerce' ),
                $detail
            )
            : __( 'Invoice generation failed. Check WooCommerce > Status > Logs (source: gofactox-e-invoicing-for-woocommerce).', 'gofactox-e-invoicing-for-woocommerce' );
        wp_send_json_error( [ 'message' => $message ] );
    }

    /**
     * AJAX handler for manual credit note generation.
     */
    public static function ajax_generate_credit_note(): void {
        check_ajax_referer( 'gofactox_generate_invoice' );

        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( [
                'message' => __( 'You do not have permission to generate credit notes.', 'gofactox-e-invoicing-for-woocommerce' ),
            ] );
        }

        if ( ! GOFACTOX_License::is_pro() ) {
            wp_send_json_error( [
                'message' => __( 'Credit notes are a Pro feature. Upgrade your plan to enable refund-to-credit-note generation.', 'gofactox-e-invoicing-for-woocommerce' ),
            ] );
        }

        $refund_id = isset( $_POST['refund_id'] ) ? (int) sanitize_text_field( wp_unslash( $_POST['refund_id'] ) ) : 0;
        $refund    = wc_get_order( $refund_id );

        if ( ! $refund instanceof \WC_Order_Refund ) {
            wp_send_json_error( [
                'message' => __( 'Refund not found.', 'gofactox-e-invoicing-for-woocommerce' ),
            ] );
        }

        $config_errors = GOFACTOX_Invoice::get_validation_errors();
        if ( ! empty( $config_errors ) ) {
            wp_send_json_error( [
                'message'        => __( 'Company information is incomplete. Fill the missing fields before generating a credit note.', 'gofactox-e-invoicing-for-woocommerce' ),
                'missing_fields' => array_values( $config_errors ),
                'settings_url'   => GOFACTOX_Invoice::get_settings_url(),
            ] );
        }

        $parent_order = wc_get_order( $refund->get_parent_id() );
        if ( ! $parent_order instanceof \WC_Order || ! $parent_order->get_meta( '_gofactox_invoice_id' ) ) {
            wp_send_json_error( [
                'message' => __( 'Cannot create credit note: the parent order has no invoice yet. Generate the invoice first.', 'gofactox-e-invoicing-for-woocommerce' ),
            ] );
        }

        // For regeneration, delete existing credit note data.
        $existing_id = $refund->get_meta( '_gofactox_credit_note_id' );
        if ( $existing_id ) {
            $old_path = GOFACTOX_Invoice::get_pdf_path( (int) $existing_id );
            if ( $old_path && file_exists( $old_path ) ) {
                wp_delete_file( $old_path );
            }
            wp_delete_post( (int) $existing_id, true );
            $refund->delete_meta_data( '_gofactox_credit_note_id' );
            $refund->delete_meta_data( '_gofactox_credit_note_number' );
            $refund->save();
        }

        $result = self::generate_credit_note_for_refund( $refund );

        if ( $result ) {
            wp_send_json_success( [ 'path' => $result ] );
        }

        $detail = self::get_last_error();
        $message = $detail
            ? sprintf(
                /* translators: %s: detailed error message from the generator */
                __( 'Credit note generation failed: %s', 'gofactox-e-invoicing-for-woocommerce' ),
                $detail
            )
            : __( 'Credit note generation failed. Check WooCommerce > Status > Logs.', 'gofactox-e-invoicing-for-woocommerce' );
        wp_send_json_error( [ 'message' => $message ] );
    }
}
