<?php
/**
 * Generación de Presupuestos Extension
 *
 * This extension adds quote/estimate generation functionality to Freefactu.
 * Quotes can be converted to invoices when accepted.
 *
 * @package Freefactu
 * @subpackage Extensions/Presupuestos
 * @since 1.2.0
 */

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

/**
 * Class Freefactu_Presupuestos
 *
 * Main class for the "Generación de Presupuestos" extension.
 * Handles:
 * - Quote creation and management
 * - PDF generation for quotes
 * - Quote to invoice conversion
 * - Extension settings within the Configuración tab
 *
 * @since 1.2.0
 */
class Freefactu_Presupuestos {

    /**
     * The single instance of this class.
     *
     * @var Freefactu_Presupuestos|null
     */
    private static $instance = null;

    /**
     * Extension ID.
     *
     * @var string
     */
    const EXTENSION_ID = 'presupuestos';

    /**
     * Option key for extension settings.
     *
     * @var string
     */
    const OPTION_KEY = 'freefactu_presupuestos_settings';

    /**
     * Database table name (without prefix).
     *
     * @var string
     */
    const TABLE_NAME = 'freefactu_presupuestos';

    /**
     * Get the singleton instance.
     *
     * @return Freefactu_Presupuestos
     */
    public static function instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Constructor.
     */
    private function __construct() {
        $this->init_hooks();
        $this->ensure_table_exists();
    }

    /**
     * Initialize hooks.
     */
    private function init_hooks() {
        // Add settings section to Configuración tab
        add_action( 'freefactu_settings_sections', array( $this, 'render_settings_section' ), 25 );

        // Add numbering section to Numeración tab
        add_action( 'freefactu_numbering_sections', array( $this, 'render_numbering_section' ), 10 );

        // Register extension settings
        add_action( 'admin_init', array( $this, 'register_settings' ) );

        // Add presupuesto button to order list
        add_action( 'woocommerce_admin_order_actions_end', array( $this, 'add_order_list_action' ), 15 );

        // Add meta box to order view
        add_action( 'add_meta_boxes', array( $this, 'add_presupuesto_meta_box' ) );

        // AJAX handlers
        add_action( 'wp_ajax_freefactu_create_presupuesto', array( $this, 'ajax_create_presupuesto' ) );
        add_action( 'wp_ajax_freefactu_convert_to_invoice', array( $this, 'ajax_convert_to_invoice' ) );
        add_action( 'wp_ajax_freefactu_presupuesto_set_active_series', array( $this, 'ajax_set_active_series' ) );
        add_action( 'wp_ajax_freefactu_presupuesto_create_series', array( $this, 'ajax_create_series' ) );
        add_action( 'wp_ajax_freefactu_presupuesto_delete_series', array( $this, 'ajax_delete_series' ) );

        // Download handler
        add_action( 'admin_post_freefactu_download_presupuesto', array( $this, 'handle_download_presupuesto' ) );

        // Enqueue scripts
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
    }

    /**
     * Get extension settings.
     *
     * @return array Settings array with defaults.
     */
    public static function get_settings() {
        $defaults = array(
            'enabled'              => true,
            'prefix'               => 'PRES-',
            'suffix'               => '',
            'padding'              => 4,
            'next_number'          => 1,
            'validity_days'        => 30,
            'show_validity_date'   => true,
            'auto_number'          => true,
            'pdf_title'            => __( 'Presupuesto', 'freefactu' ),
            'pdf_footer_text'      => __( 'Este presupuesto es válido por {validity_days} días desde la fecha de emisión.', 'freefactu' ),
        );

        $settings = get_option( self::OPTION_KEY, array() );
        
        return wp_parse_args( $settings, $defaults );
    }

    /**
     * Update extension settings.
     *
     * @param array $settings Settings to save.
     * @return bool True if updated successfully.
     */
    public static function update_settings( $settings ) {
        return update_option( self::OPTION_KEY, $settings );
    }

    /**
     * Register extension settings for WordPress Settings API.
     */
    public function register_settings() {
        register_setting( 
            'freefactu_settings_group', 
            self::OPTION_KEY, 
            array( $this, 'sanitize_settings' ) 
        );
    }

    /**
     * Sanitize extension settings.
     *
     * @param array $input Raw input from form.
     * @return array Sanitized settings.
     */
    public function sanitize_settings( $input ) {
        $sanitized = array();

        // Boolean fields
        $boolean_fields = array(
            'enabled',
            'show_validity_date',
            'auto_number',
        );

        foreach ( $boolean_fields as $field ) {
            $sanitized[ $field ] = ! empty( $input[ $field ] );
        }

        // Text fields
        $text_fields = array( 'prefix', 'suffix', 'pdf_title', 'pdf_footer_text' );
        foreach ( $text_fields as $field ) {
            if ( isset( $input[ $field ] ) ) {
                $sanitized[ $field ] = sanitize_text_field( $input[ $field ] );
            }
        }

        // Integer fields
        if ( isset( $input['padding'] ) ) {
            $sanitized['padding'] = absint( $input['padding'] );
            if ( $sanitized['padding'] < 1 ) $sanitized['padding'] = 1;
            if ( $sanitized['padding'] > 10 ) $sanitized['padding'] = 10;
        }

        if ( isset( $input['next_number'] ) ) {
            $sanitized['next_number'] = absint( $input['next_number'] );
            if ( $sanitized['next_number'] < 1 ) $sanitized['next_number'] = 1;
        }

        if ( isset( $input['validity_days'] ) ) {
            $sanitized['validity_days'] = absint( $input['validity_days'] );
            if ( $sanitized['validity_days'] < 1 ) $sanitized['validity_days'] = 1;
        }

        return $sanitized;
    }

    /**
     * Ensure the presupuestos table exists.
     */
    private function ensure_table_exists() {
        global $wpdb;
        $table_name = $wpdb->prefix . self::TABLE_NAME;

        // Check cache first to avoid unnecessary DB queries
        $table_exists = wp_cache_get( 'freefactu_presupuestos_table_exists', 'freefactu' );

        if ( false === $table_exists ) {
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery
            $table_exists = $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) === $table_name;
            wp_cache_set( 'freefactu_presupuestos_table_exists', $table_exists, 'freefactu', DAY_IN_SECONDS );
        }

        if ( ! $table_exists ) {
            $this->create_table();
            wp_cache_delete( 'freefactu_presupuestos_table_exists', 'freefactu' );
        }
    }

    /**
     * Create the presupuestos database table.
     */
    private function create_table() {
        global $wpdb;
        $table_name = $wpdb->prefix . self::TABLE_NAME;
        $charset_collate = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE $table_name (
            id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
            order_id bigint(20) unsigned NOT NULL,
            presupuesto_number varchar(50) NOT NULL,
            presupuesto_date datetime NOT NULL,
            validity_date datetime DEFAULT NULL,
            status varchar(20) NOT NULL DEFAULT 'draft',
            total decimal(10,2) NOT NULL DEFAULT 0.00,
            pdf_path varchar(255) DEFAULT NULL,
            converted_to_invoice_id bigint(20) unsigned DEFAULT NULL,
            snapshot longtext DEFAULT NULL,
            created_at datetime NOT NULL,
            updated_at datetime NOT NULL,
            PRIMARY KEY (id),
            KEY order_id (order_id),
            KEY presupuesto_number (presupuesto_number),
            KEY status (status)
        ) $charset_collate;";

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        dbDelta( $sql );
    }

    /**
     * Get presupuesto by order ID.
     *
     * @param int $order_id Order ID.
     * @return object|null Presupuesto object or null.
     */
    public static function get_presupuesto_by_order_id( $order_id ) {
        global $wpdb;
        $table_name = $wpdb->prefix . self::TABLE_NAME;
        
        $cache_key = 'presupuesto_order_' . $order_id;
        $presupuesto = wp_cache_get( $cache_key, 'freefactu_presupuestos' );

        if ( false === $presupuesto ) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $presupuesto = $wpdb->get_row(
                $wpdb->prepare(
                    "SELECT * FROM " . esc_sql( $table_name ) . " WHERE order_id = %d ORDER BY id DESC LIMIT 1",
                    $order_id
                )
            );
            wp_cache_set( $cache_key, $presupuesto, 'freefactu_presupuestos' );
        }
        
        return $presupuesto;
    }

    /**
     * Generate next presupuesto number using the Extension Series Store.
     *
     * @return string|WP_Error Formatted presupuesto number or error.
     */
    public function generate_presupuesto_number() {
        // Ensure default series exists
        $this->ensure_default_series();
        
        // Get active series
        $series = Freefactu_Extension_Series_Store::get_active_series( self::EXTENSION_ID );
        
        if ( ! $series ) {
            // Fallback to settings-based numbering if no series exists
            $settings = self::get_settings();
            $prefix = $settings['prefix'];
            $suffix = $settings['suffix'];
            $padding = (int) $settings['padding'];
            $next_number = (int) $settings['next_number'];

            $formatted_number = $prefix . str_pad( $next_number, $padding, '0', STR_PAD_LEFT ) . $suffix;

            // Increment for next use
            $settings['next_number'] = $next_number + 1;
            self::update_settings( $settings );

            return $formatted_number;
        }
        
        // Use the series to generate number
        $number = Freefactu_Extension_Series_Store::increment( $series->id );
        
        if ( is_wp_error( $number ) ) {
            return $number;
        }
        
        return Freefactu_Extension_Series_Store::format_number( $series, $number );
    }
    
    /**
     * Ensure default presupuesto series exists.
     */
    private function ensure_default_series() {
        $settings = self::get_settings();
        
        Freefactu_Extension_Series_Store::ensure_default_series(
            self::EXTENSION_ID,
            array(
                'name'    => __( 'Serie Principal', 'freefactu' ),
                'prefix'  => $settings['prefix'],
                'suffix'  => $settings['suffix'],
                'padding' => (int) $settings['padding'],
            )
        );
    }

    /**
     * Add presupuesto action button to WooCommerce order list.
     * Uses the same HTML structure as the invoice button for consistent styling.
     *
     * @param WC_Order $order The order object.
     */
    public function add_order_list_action( $order ) {
        if ( 'trash' === $order->get_status() ) {
            return;
        }

        $presupuesto = self::get_presupuesto_by_order_id( $order->get_id() );
        $button_state = $this->get_button_state( $presupuesto );

        // Use extension's own icon file (copy of invoice icon, can be customized)
        $icon_url = FREEFACTU_PLUGIN_URL . 'extensions/presupuestos/assets/freefactu-presupuesto.svg';
        
        // Build data attributes
        // freefactu-invoice-action provides the base button styling (border, background, padding)
        // freefactu-presupuesto-action is for JavaScript targeting
        echo '<a href="' . esc_url( $button_state['href'] ) . '" class="tips freefactu-invoice-action freefactu-presupuesto-action ' . esc_attr( $button_state['classes'] ) . '" data-order-id="' . esc_attr( $order->get_id() ) . '" data-presupuesto-id="' . esc_attr( $presupuesto ? $presupuesto->id : 0 ) . '" data-tip="' . esc_attr( $button_state['tooltip'] ) . '">';
        echo '<span class="freefactu-icon-wrapper">';
        echo '<img src="' . esc_url( $icon_url ) . '" class="freefactu-pdf-icon" alt="Presupuesto" />';
        echo wp_kses( $button_state['badge'], array(
            'svg' => array( 'class' => true, 'width' => true, 'height' => true, 'viewbox' => true ),
            'circle' => array( 'cx' => true, 'cy' => true, 'r' => true, 'fill' => true ),
            'path' => array( 'd' => true, 'stroke' => true, 'stroke-width' => true, 'fill' => true ),
        ) );
        echo '</span>';
        echo '<span class="freefactu-icon-text">' . esc_html( $button_state['text'] ) . '</span>';
        echo '</a>';
    }

    /**
     * Get button state based on presupuesto status.
     *
     * @param object|null $presupuesto Presupuesto object.
     * @return array Button state data.
     */
    private function get_button_state( $presupuesto ) {
        if ( ! $presupuesto ) {
            return array(
                'href'    => '#',
                'classes' => '',
                'tooltip' => __( 'Crear Presupuesto', 'freefactu' ),
                'badge'   => '',
                'text'    => __( 'Crear Presupuesto', 'freefactu' ),
            );
        }

        // Generate download URL for existing presupuestos
        $download_url = admin_url( 'admin-post.php?action=freefactu_download_presupuesto&id=' . $presupuesto->id . '&_wpnonce=' . wp_create_nonce( 'download_presupuesto_' . $presupuesto->id ) );

        switch ( $presupuesto->status ) {
            case 'created':
                return array(
                    'href'    => $download_url,
                    'classes' => 'exists',
                    'tooltip' => __( 'Ver Presupuesto', 'freefactu' ),
                    'badge'   => '<svg class="freefactu-status-badge freefactu-badge-success" width="12" height="12" viewBox="0 0 24 24"><circle cx="12" cy="12" r="11" fill="#46b450"/><path d="M9 12l2 2 4-4" stroke="#fff" stroke-width="2" fill="none"/></svg>',
                    'text'    => __( 'Ver Presupuesto', 'freefactu' ),
                );
            case 'converted':
                return array(
                    'href'    => $download_url,
                    'classes' => 'converted',
                    'tooltip' => __( 'Presupuesto convertido a factura', 'freefactu' ),
                    'badge'   => '<svg class="freefactu-status-badge freefactu-badge-info" width="12" height="12" viewBox="0 0 24 24"><circle cx="12" cy="12" r="11" fill="#0073aa"/><path d="M11 7h2v6h-2zm0 8h2v2h-2z" fill="#fff"/></svg>',
                    'text'    => __( 'Convertido', 'freefactu' ),
                );
            default:
                return array(
                    'href'    => '#',
                    'classes' => '',
                    'tooltip' => __( 'Crear Presupuesto', 'freefactu' ),
                    'badge'   => '',
                    'text'    => __( 'Crear Presupuesto', 'freefactu' ),
                );
        }
    }

    /**
     * Add meta box for presupuesto actions on single order view.
     */
    public function add_presupuesto_meta_box() {
        $screen = wc_get_container()->get( \Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled()
            ? wc_get_page_screen_id( 'shop-order' )
            : 'shop_order';

        add_meta_box(
            'freefactu-presupuesto-actions',
            __( 'Presupuesto', 'freefactu' ),
            array( $this, 'render_presupuesto_meta_box' ),
            $screen,
            'side',
            'default'
        );
    }

    /**
     * Render the presupuesto meta box content.
     *
     * @param WP_Post|WC_Order $post_or_order The post object or order object.
     */
    public function render_presupuesto_meta_box( $post_or_order ) {
        if ( $post_or_order instanceof WC_Order ) {
            $order = $post_or_order;
        } else {
            $order = wc_get_order( $post_or_order->ID );
        }

        if ( ! $order ) {
            echo '<p>' . esc_html__( 'Pedido no encontrado.', 'freefactu' ) . '</p>';
            return;
        }

        $presupuesto = self::get_presupuesto_by_order_id( $order->get_id() );
        $button_state = $this->get_button_state( $presupuesto );
        $icon_url = FREEFACTU_PLUGIN_URL . 'extensions/presupuestos/assets/presupuesto-icon.svg';

        echo '<div class="freefactu-presupuesto-meta-box-content">';

        if ( $presupuesto ) {
            echo '<div class="freefactu-presupuesto-info">';
            echo '<p><strong>' . esc_html__( 'Número:', 'freefactu' ) . '</strong> ' . esc_html( $presupuesto->presupuesto_number ) . '</p>';
            echo '<p><strong>' . esc_html__( 'Fecha:', 'freefactu' ) . '</strong> ' . esc_html( date_i18n( get_option( 'date_format' ), strtotime( $presupuesto->presupuesto_date ) ) ) . '</p>';
            
            if ( $presupuesto->validity_date ) {
                $is_expired = strtotime( $presupuesto->validity_date ) < time();
                $validity_class = $is_expired ? 'expired' : '';
                echo '<p class="' . esc_attr( $validity_class ) . '"><strong>' . esc_html__( 'Válido hasta:', 'freefactu' ) . '</strong> ' . esc_html( date_i18n( get_option( 'date_format' ), strtotime( $presupuesto->validity_date ) ) );
                if ( $is_expired ) {
                    echo ' <span class="freefactu-status-label freefactu-status-label--expired">(' . esc_html__( 'Expirado', 'freefactu' ) . ')</span>';
                }
                echo '</p>';
            }

            echo '<p><strong>' . esc_html__( 'Estado:', 'freefactu' ) . '</strong> ';
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Hardcoded HTML + esc_html__().
            echo $presupuesto->status === 'converted' 
                ? '<span class="freefactu-status-label freefactu-status-label--converted">' . esc_html__( 'Convertido a factura', 'freefactu' ) . '</span>'
                : '<span class="freefactu-status-label freefactu-status-label--created">' . esc_html__( 'Creado', 'freefactu' ) . '</span>';
            echo '</p>';
            echo '</div>';

            // Download button
            if ( ! empty( $presupuesto->pdf_path ) ) {
                $download_url = admin_url( 'admin-post.php?action=freefactu_download_presupuesto&id=' . $presupuesto->id . '&_wpnonce=' . wp_create_nonce( 'download_presupuesto_' . $presupuesto->id ) );
                echo '<p><a href="' . esc_url( $download_url ) . '" class="button">' . esc_html__( 'Descargar PDF', 'freefactu' ) . '</a></p>';
            }

            // Convert to invoice button (if not already converted and invoice doesn't exist)
            if ( $presupuesto->status !== 'converted' ) {
                $invoice = Freefactu_DB::get_invoice_by_order_id( $order->get_id() );
                if ( ! $invoice ) {
                    echo '<p><button type="button" class="button freefactu-convert-to-invoice" data-order-id="' . esc_attr( $order->get_id() ) . '" data-presupuesto-id="' . esc_attr( $presupuesto->id ) . '">' . esc_html__( 'Convertir a Factura', 'freefactu' ) . '</button></p>';
                }
            }
        } else {
            // Create presupuesto button
            echo '<p class="freefactu-presupuesto-buttons">';
            printf(
                '<a href="#" class="button freefactu-presupuesto-action" data-order-id="%d">
                    <img src="%s" class="freefactu-icon-inline" alt="" />
                    %s
                </a>',
                esc_attr( $order->get_id() ),
                esc_url( $icon_url ),
                esc_html__( 'Crear Presupuesto', 'freefactu' )
            );
            echo '</p>';
        }

        echo '</div>';
    }

    /**
     * AJAX handler for creating a presupuesto.
     */
    public function ajax_create_presupuesto() {
        check_ajax_referer( 'freefactu_presupuesto_nonce', 'nonce' );

        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array( 'message' => __( 'Permiso denegado.', 'freefactu' ) ) );
        }

        $order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;
        if ( ! $order_id ) {
            wp_send_json_error( array( 'message' => __( 'ID de pedido inválido.', 'freefactu' ) ) );
        }

        $order = wc_get_order( $order_id );
        if ( ! $order ) {
            wp_send_json_error( array( 'message' => __( 'Pedido no encontrado.', 'freefactu' ) ) );
        }

        // Check if presupuesto already exists
        $existing = self::get_presupuesto_by_order_id( $order_id );
        if ( $existing ) {
            wp_send_json_error( array( 'message' => __( 'Ya existe un presupuesto para este pedido.', 'freefactu' ) ) );
        }

        $result = $this->create_presupuesto( $order );

        if ( is_wp_error( $result ) ) {
            wp_send_json_error( array( 'message' => $result->get_error_message() ) );
        }

        wp_send_json_success( array(
            'message'             => __( 'Presupuesto creado correctamente.', 'freefactu' ),
            'presupuesto_number'  => $result['presupuesto_number'],
            'download_url'        => $result['download_url'],
        ) );
    }

    /**
     * Create a presupuesto for an order.
     *
     * @param WC_Order $order The order object.
     * @return array|WP_Error Result array or error.
     */
    public function create_presupuesto( $order ) {
        global $wpdb;
        $table_name = $wpdb->prefix . self::TABLE_NAME;
        $settings = self::get_settings();

        $presupuesto_number = $this->generate_presupuesto_number();
        $presupuesto_date = current_time( 'mysql' );
        $validity_date = gmdate( 'Y-m-d H:i:s', strtotime( '+' . $settings['validity_days'] . ' days' ) );

        // Create snapshot of order data
        $snapshot = $this->create_order_snapshot( $order );

        // Insert into database
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        $inserted = $wpdb->insert(
            $table_name,
            array(
                'order_id'           => $order->get_id(),
                'presupuesto_number' => $presupuesto_number,
                'presupuesto_date'   => $presupuesto_date,
                'validity_date'      => $validity_date,
                'status'             => 'created',
                'total'              => $order->get_total(),
                'snapshot'           => wp_json_encode( $snapshot ),
                'created_at'         => current_time( 'mysql' ),
                'updated_at'         => current_time( 'mysql' ),
            ),
            array( '%d', '%s', '%s', '%s', '%s', '%f', '%s', '%s', '%s' )
        );

        if ( $inserted ) {
            // Invalidate caches
            wp_cache_delete( 'presupuesto_order_' . $order->get_id(), 'freefactu_presupuestos' );
            wp_cache_delete( 'freefactu_presupuestos_count', 'freefactu_presupuestos' );
        }

        if ( ! $inserted ) {
            return new WP_Error( 'db_error', __( 'Error al guardar el presupuesto.', 'freefactu' ) );
        }

        $presupuesto_id = $wpdb->insert_id;

        // Generate PDF
        $pdf_result = $this->generate_pdf( $presupuesto_id, $order, $presupuesto_number, $snapshot );
        
        if ( is_wp_error( $pdf_result ) ) {
            return $pdf_result;
        }

        // Update with PDF path
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        $wpdb->update(
            $table_name,
            array( 'pdf_path' => $pdf_result['relative_path'] ),
            array( 'id' => $presupuesto_id ),
            array( '%s' ),
            array( '%d' )
        );

        // Invalidate caches
        wp_cache_delete( 'presupuesto_id_' . $presupuesto_id, 'freefactu_presupuestos' );
        wp_cache_delete( 'presupuesto_order_' . $order->get_id(), 'freefactu_presupuestos' );

        $download_url = admin_url( 'admin-post.php?action=freefactu_download_presupuesto&id=' . $presupuesto_id . '&_wpnonce=' . wp_create_nonce( 'download_presupuesto_' . $presupuesto_id ) );

        /**
         * Fires after a presupuesto is created.
         *
         * @param int      $presupuesto_id     The presupuesto ID.
         * @param WC_Order $order              The order object.
         * @param string   $presupuesto_number The presupuesto number.
         */
        do_action( 'freefactu_presupuesto_created', $presupuesto_id, $order, $presupuesto_number );

        return array(
            'presupuesto_id'     => $presupuesto_id,
            'presupuesto_number' => $presupuesto_number,
            'download_url'       => $download_url,
        );
    }

    /**
     * Create order snapshot for presupuesto.
     *
     * @param WC_Order $order The order object.
     * @return array Order snapshot data.
     */
    private function create_order_snapshot( $order ) {
        $items = array();
        foreach ( $order->get_items() as $item ) {
            $items[] = array(
                'name'     => $item->get_name(),
                'quantity' => $item->get_quantity(),
                'subtotal' => $item->get_subtotal(),
                'total'    => $item->get_total(),
                'tax'      => $item->get_total_tax(),
            );
        }

        return array(
            'order_id'         => $order->get_id(),
            'customer_name'    => $order->get_formatted_billing_full_name(),
            'customer_email'   => $order->get_billing_email(),
            'customer_address' => $order->get_formatted_billing_address(),
            'customer_nif'     => $order->get_meta( '_billing_nif' ),
            'items'            => $items,
            'subtotal'         => $order->get_subtotal(),
            'total_tax'        => $order->get_total_tax(),
            'total'            => $order->get_total(),
            'currency'         => $order->get_currency(),
        );
    }

    /**
     * Generate PDF for presupuesto.
     *
     * @param int      $presupuesto_id     Presupuesto ID.
     * @param WC_Order $order              Order object.
     * @param string   $presupuesto_number Presupuesto number.
     * @param array    $snapshot           Order snapshot.
     * @return array|WP_Error PDF paths or error.
     */
    private function generate_pdf( $presupuesto_id, $order, $presupuesto_number, $snapshot ) {
        // Check DOMPDF availability
        if ( class_exists( 'Freefactu_Vendor\Dompdf\Dompdf' ) ) {
            $dompdf = new Freefactu_Vendor\Dompdf\Dompdf();
        } elseif ( class_exists( 'Dompdf\Dompdf' ) ) {
            $dompdf = new Dompdf\Dompdf();
        } else {
            return new WP_Error( 'dompdf_missing', __( 'DOMPDF no está disponible.', 'freefactu' ) );
        }

        $settings = self::get_settings();
        $html = $this->generate_pdf_html( $order, $presupuesto_number, $snapshot, $settings );

        $dompdf->loadHtml( $html );
        $dompdf->setPaper( 'A4', 'portrait' );
        $dompdf->render();

        // Save PDF
        $upload_dir = wp_upload_dir();
        $pdf_dir = $upload_dir['basedir'] . '/freefactu/presupuestos/' . gmdate( 'Y/m' );
        
        if ( ! file_exists( $pdf_dir ) ) {
            wp_mkdir_p( $pdf_dir );
        }

        $filename = 'presupuesto-' . sanitize_file_name( $presupuesto_number ) . '.pdf';
        $pdf_path = $pdf_dir . '/' . $filename;
        $relative_path = 'freefactu/presupuestos/' . gmdate( 'Y/m' ) . '/' . $filename;

        file_put_contents( $pdf_path, $dompdf->output() );

        return array(
            'absolute_path' => $pdf_path,
            'relative_path' => $relative_path,
        );
    }

    /**
     * Generate HTML content for presupuesto PDF using template.
     *
     * @param WC_Order $order              Order object.
     * @param string   $presupuesto_number Presupuesto number.
     * @param array    $snapshot           Order snapshot.
     * @param array    $settings           Extension settings.
     * @return string HTML content.
     */
    private function generate_pdf_html( $order, $presupuesto_number, $snapshot, $settings ) {
        $options = get_option( 'freefactu_settings' );
        
        // Prepare company data (same structure as invoice template)
        $company = array(
            'name'      => isset( $options['company_name'] ) ? $options['company_name'] : '',
            'nif'       => isset( $options['company_nif'] ) ? $options['company_nif'] : '',
            'email'     => isset( $options['company_email'] ) ? $options['company_email'] : '',
            'phone'     => isset( $options['company_phone'] ) ? $options['company_phone'] : '',
            'address'   => isset( $options['company_address'] ) ? $options['company_address'] : '',
            'logo'      => isset( $options['company_logo'] ) ? $options['company_logo'] : '',
            'site_name' => get_bloginfo( 'name' ),
        );

        // Prepare customer data (same structure as invoice template)
        $customer = array(
            'name'       => $order->get_formatted_billing_full_name(),
            'company'    => $order->get_billing_company(),
            'nif'        => $order->get_meta( '_billing_nif' ),
            'email'      => $order->get_billing_email(),
            'phone'      => $order->get_billing_phone(),
            'address_1'  => $order->get_billing_address_1(),
            'address_2'  => $order->get_billing_address_2(),
            'city'       => $order->get_billing_city(),
            'postcode'   => $order->get_billing_postcode(),
            'country'    => WC()->countries->countries[ $order->get_billing_country() ] ?? $order->get_billing_country(),
        );

        // Prepare items (same structure as invoice template)
        $items = array();
        foreach ( $order->get_items() as $item ) {
            $qty = $item->get_quantity();
            $total = $item->get_total();
            $unit_price = $qty > 0 ? $total / $qty : 0;
            
            // Calculate tax rate
            $tax_total = $item->get_total_tax();
            $tax_rate = $total > 0 ? round( ( $tax_total / $total ) * 100 ) : 0;
            
            $items[] = array(
                'name'       => $item->get_name(),
                'quantity'   => $qty,
                'unit_price' => $unit_price,
                'tax_rate'   => $tax_rate,
                'total'      => $total,
            );
        }

        // Prepare tax breakdown
        $tax_breakdown = array();
        foreach ( $order->get_tax_totals() as $tax ) {
            $rate = floatval( str_replace( '%', '', $tax->label ) );
            
            // Clean up tax name to prevent double percentage display (e.g. "IVA (21%) (21%)")
            // Check for "(X%)" pattern where X matches the rate
            $name = $tax->label;
            $percent_string = '(' . $rate . '%)';
            if ( strpos( $name, $percent_string ) !== false ) {
                $name = trim( str_replace( $percent_string, '', $name ) );
            }
            
            $tax_breakdown[] = array(
                'name'   => $name,
                'rate'   => $rate,
                'base'   => $order->get_subtotal(),
                'amount' => floatval( $tax->amount ),
            );
        }

        // Prepare totals
        $totals = array(
            'subtotal'  => $order->get_subtotal(),
            'tax_total' => $order->get_total_tax(),
            'total'     => $order->get_total(),
        );

        // Footer text with placeholder replaced
        $footer_text = str_replace( '{validity_days}', $settings['validity_days'], $settings['pdf_footer_text'] );

        // Prepare template data
        $data = array(
            'presupuesto_number' => $presupuesto_number,
            'presupuesto_date'   => date_i18n( get_option( 'date_format' ) ),
            'validity_date'      => $settings['show_validity_date'] ? date_i18n( get_option( 'date_format' ), strtotime( '+' . $settings['validity_days'] . ' days' ) ) : '',
            'validity_days'      => $settings['validity_days'],
            'company'            => $company,
            'customer'           => $customer,
            'items'              => $items,
            'totals'             => $totals,
            'tax_breakdown'      => $tax_breakdown,
            'order_id'           => $order->get_id(),
            'pdf_title'          => $settings['pdf_title'],
            'pdf_footer'         => $footer_text,
        );

        // Load template
        $template_path = dirname( __FILE__ ) . '/templates/presupuesto.php';
        
        if ( file_exists( $template_path ) ) {
            ob_start();
            include $template_path;
            return ob_get_clean();
        }

        // Fallback: return error message as HTML
        return '<html><body><h1>' . __( 'Error: Template not found', 'freefactu' ) . '</h1></body></html>';
    }

    /**
     * Handle presupuesto PDF download.
     */
    public function handle_download_presupuesto() {
        $id = isset( $_GET['id'] ) ? absint( $_GET['id'] ) : 0;
        
        $nonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) : '';
        if ( ! wp_verify_nonce( $nonce, 'download_presupuesto_' . $id ) ) {
            wp_die( esc_html__( 'Enlace expirado.', 'freefactu' ) );
        }

        global $wpdb;
        $table_name = $wpdb->prefix . self::TABLE_NAME;
        // Check cache first
        $cache_key = 'presupuesto_id_' . $id;
        $presupuesto = wp_cache_get( $cache_key, 'freefactu_presupuestos' );

        if ( false === $presupuesto ) {
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery
            $presupuesto = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id ) );
            if ( $presupuesto ) {
                wp_cache_set( $cache_key, $presupuesto, 'freefactu_presupuestos' );
            }
        }

        if ( ! $presupuesto || empty( $presupuesto->pdf_path ) ) {
            wp_die( esc_html__( 'Presupuesto no encontrado.', 'freefactu' ) );
        }

        $upload_dir = wp_upload_dir();
        $pdf_path = $upload_dir['basedir'] . '/' . $presupuesto->pdf_path;

        if ( ! file_exists( $pdf_path ) ) {
            wp_die( esc_html__( 'Archivo PDF no encontrado.', 'freefactu' ) );
        }

        header( 'Content-Type: application/pdf' );
        header( 'Content-Disposition: inline; filename="' . sanitize_file_name( 'presupuesto-' . $presupuesto->presupuesto_number . '.pdf' ) . '"' );
        header( 'Content-Length: ' . filesize( $pdf_path ) );
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile
        readfile( $pdf_path );
        exit;
    }

    /**
     * AJAX handler for converting presupuesto to invoice.
     */
    public function ajax_convert_to_invoice() {
        check_ajax_referer( 'freefactu_presupuesto_nonce', 'nonce' );

        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array( 'message' => __( 'Permiso denegado.', 'freefactu' ) ) );
        }

        $presupuesto_id = isset( $_POST['presupuesto_id'] ) ? absint( $_POST['presupuesto_id'] ) : 0;
        $order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;

        if ( ! $presupuesto_id || ! $order_id ) {
            wp_send_json_error( array( 'message' => __( 'Datos inválidos.', 'freefactu' ) ) );
        }

        global $wpdb;
        $table_name = $wpdb->prefix . self::TABLE_NAME;

        // Mark as converted
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        $wpdb->update(
            $table_name,
            array(
                'status'     => 'converted',
                'updated_at' => current_time( 'mysql' ),
            ),
            array( 'id' => $presupuesto_id ),
            array( '%s', '%s' ),
            array( '%d' )
        );

        // Invalidate caches
        wp_cache_delete( 'presupuesto_id_' . $presupuesto_id, 'freefactu_presupuestos' );
        wp_cache_delete( 'presupuesto_order_' . $order_id, 'freefactu_presupuestos' );

        /**
         * Fires when a presupuesto is about to be converted to invoice.
         *
         * @param int $presupuesto_id Presupuesto ID.
         * @param int $order_id       Order ID.
         */
        do_action( 'freefactu_presupuesto_converting', $presupuesto_id, $order_id );

        wp_send_json_success( array(
            'message'  => __( 'Presupuesto marcado como convertido. Ahora puedes crear la factura.', 'freefactu' ),
            'order_id' => $order_id,
        ) );
    }

    /**
     * Enqueue extension scripts.
     *
     * @param string $hook Current admin page hook.
     */
    public function enqueue_scripts( $hook ) {
        // Check if this is the Freefactu admin page
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $is_freefactu_page = ( isset( $_GET['page'] ) && strpos( sanitize_text_field( wp_unslash( $_GET['page'] ) ), 'freefactu' ) !== false );
        
        // Check if this is a WooCommerce order page
        $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
        $is_woocommerce_page = $screen && (
            strpos( $screen->id, 'woocommerce' ) !== false ||
            strpos( $screen->id, 'shop_order' ) !== false ||
            strpos( $screen->id, 'edit-shop_order' ) !== false ||
            ( isset( $screen->post_type ) && $screen->post_type === 'shop_order' )
        );
        
        // Only load on Freefactu pages or WooCommerce order pages
        if ( ! $is_freefactu_page && ! $is_woocommerce_page ) {
            return;
        }

        // Register and enqueue the presupuestos script
        wp_enqueue_script(
            'freefactu-presupuestos',
            FREEFACTU_PLUGIN_URL . 'assets/js/freefactu-presupuestos.js',
            array( 'jquery', 'freefactu-admin' ),
            FREEFACTU_VERSION,
            true
        );

        // Localize script with nonce and i18n strings
        wp_localize_script( 'freefactu-presupuestos', 'freefactu_presupuestos_params', array(
            'nonce'        => wp_create_nonce( 'freefactu_presupuesto_nonce' ),
            'series_nonce' => wp_create_nonce( 'freefactu_presupuesto_series_nonce' ),
            'i18n'         => array(
                'confirm_create'        => __( '¿Crear presupuesto para este pedido?', 'freefactu' ),
                'confirm_convert'       => __( '¿Convertir este presupuesto a factura?', 'freefactu' ),
                'confirm_delete_series' => __( '¿Eliminar esta serie?', 'freefactu' ),
                'creating'              => __( 'Creando...', 'freefactu' ),
                'error'                 => __( 'Error', 'freefactu' ),
                'connection_error'      => __( 'Error de conexión', 'freefactu' ),
                'enter_name'            => __( 'Por favor, introduce un nombre.', 'freefactu' ),
                'error_creating_series' => __( 'Error al crear la serie', 'freefactu' ),
                'error_deleting_series' => __( 'Error al eliminar', 'freefactu' ),
            ),
        ) );

        // Add inline styles for presupuesto meta box
        wp_add_inline_style( 'freefactu-admin', $this->get_inline_styles() );
    }


    /**
     * Get inline CSS styles for presupuesto meta box.
     *
     * SECURITY NOTE: Returns static CSS only - no user input is interpolated.
     * Safe for use with wp_add_inline_style().
     *
     * @return string Static CSS code with no user-controlled values.
     */
    private function get_inline_styles() {
        return "
        .freefactu-presupuesto-meta-box-content .freefactu-presupuesto-info {
            margin-bottom: 15px;
            padding: 10px;
            background: #f8f9fa;
            border-radius: 4px;
        }
        .freefactu-presupuesto-meta-box-content .freefactu-presupuesto-info p {
            margin: 5px 0;
        }
        .freefactu-presupuesto-meta-box-content .expired {
            color: #d63638;
        }
        ";
    }

    /**
     * Render presupuestos numbering section in Numeración tab.
     * Uses the same styling and functionality as invoice series.
     */
    public function render_numbering_section() {
        if ( ! class_exists( 'Freefactu_Extensions' ) || 
             ! Freefactu_Extensions::is_extension_active( self::EXTENSION_ID ) ) {
            return;
        }

        // Ensure default series exists
        $this->ensure_default_series();
        
        // Get all series for this extension
        $presupuesto_series = Freefactu_Extension_Series_Store::get_series_by_extension( self::EXTENSION_ID );
        ?>
        <!-- Presupuestos Section (Extension) -->
        <div class="freefactu-series-section" style="background: #fff; border: 1px solid #c3c4c7; border-radius: 4px; padding: 20px; margin-bottom: 20px;">
            <h2 style="margin-top: 0; border-bottom: 1px solid #eee; padding-bottom: 10px; display: flex; justify-content: space-between; align-items: center;">
                <span>
                    <?php esc_html_e( 'Presupuestos', 'freefactu' ); ?>
                    <span style="background: #8c8f94; color: #fff; font-size: 11px; padding: 2px 8px; border-radius: 3px; margin-left: 8px; font-weight: normal;"><?php esc_html_e( 'Extensión', 'freefactu' ); ?></span>
                </span>
                <button type="button" class="button button-primary freefactu-new-presupuesto-series-btn" data-type="presupuesto">
                    <span class="dashicons dashicons-plus-alt2"></span>
                    <?php esc_html_e( 'Nueva Serie', 'freefactu' ); ?>
                </button>
            </h2>
            
            <?php if ( empty( $presupuesto_series ) ) : ?>
            <div style="background: #f6f7f7; border-radius: 4px; padding: 30px; text-align: center;">
                <p style="margin: 0; color: #646970;">
                    <?php esc_html_e( 'No hay series de presupuestos. Crea una nueva serie para empezar a emitir presupuestos.', 'freefactu' ); ?>
                </p>
            </div>
            <?php else : ?>
            <div class="freefactu-presupuesto-series-list" data-type="presupuesto">
                <?php foreach ( $presupuesto_series as $series ) : 
                    $preview = Freefactu_Extension_Series_Store::get_preview( $series );
                    $usage_count = Freefactu_Extension_Series_Store::count_usage( $series->id );
                ?>
                <div class="freefactu-series-item <?php echo esc_attr( $series->is_active ? 'active' : '' ); ?>" 
                     style="display: flex; align-items: center; padding: 15px; border: 1px solid <?php echo esc_attr( $series->is_active ? '#2271b1' : '#dcdcde' ); ?>; border-radius: 4px; margin-bottom: 10px; background: <?php echo esc_attr( $series->is_active ? '#f0f6fc' : '#fff' ); ?>;">
                    <label style="display: flex; align-items: center; flex: 1; cursor: pointer;">
                        <input type="radio" name="freefactu_active_presupuesto_series" value="<?php echo esc_attr( $series->id ); ?>" 
                               <?php checked( $series->is_active, 1 ); ?> class="freefactu-presupuesto-series-radio" data-type="presupuesto"
                               style="margin-right: 15px; transform: scale(1.3);">
                        <div>
                            <strong style="font-size: 14px;"><?php echo esc_html( $series->name ); ?></strong>
                            <div style="color: #50575e; margin-top: 4px; font-family: 'SF Mono', Monaco, 'Courier New', monospace;">
                                <?php esc_html_e( 'Próximo:', 'freefactu' ); ?> <code style="background: #f0f0f1; padding: 2px 6px; border-radius: 3px;"><?php echo esc_html( $preview ); ?></code>
                            </div>
                            <?php if ( $usage_count > 0 ) : ?>
                            <small style="color: #757575; margin-top: 2px; display: block;">
                                <?php echo esc_html( sprintf( 
                                    /* translators: %d: Number of presupuestos */
                                    _n( '%d presupuesto emitido', '%d presupuestos emitidos', $usage_count, 'freefactu' ), 
                                    $usage_count 
                                ) ); ?>
                            </small>
                            <?php endif; ?>
                        </div>
                    </label>
                    <?php if ( ! $series->is_active && $usage_count === 0 ) : ?>
                    <button type="button" class="button freefactu-delete-presupuesto-series-btn" data-series-id="<?php echo esc_attr( $series->id ); ?>" 
                            style="margin-left: 10px;" title="<?php esc_attr_e( 'Eliminar serie', 'freefactu' ); ?>">
                        <span class="dashicons dashicons-trash" style="vertical-align: middle;"></span>
                    </button>
                    <?php elseif ( ! $series->is_active && $usage_count > 0 ) : ?>
                    <span style="margin-left: 10px; background: #dcdcde; color: #50575e; padding: 4px 10px; border-radius: 3px; font-size: 11px;">
                        <?php esc_html_e( 'Serie usada', 'freefactu' ); ?>
                    </span>
                    <?php endif; ?>
                    <?php if ( $series->is_active ) : ?>
                    <span style="margin-left: 10px; background: #2271b1; color: #fff; padding: 4px 10px; border-radius: 3px; font-size: 11px; text-transform: uppercase;">
                        <?php esc_html_e( 'Activa', 'freefactu' ); ?>
                    </span>
                    <?php endif; ?>
                </div>
                <?php endforeach; ?>
            </div>
            <?php endif; ?>
        </div>
        
        <!-- Presupuesto Series Dialog -->
        <div id="freefactu-presupuesto-series-dialog" class="freefactu-series-dialog">
            <div class="freefactu-series-dialog__content">
                <h2 class="freefactu-series-dialog__header">
                    <span><?php esc_html_e( 'Nueva Serie de Presupuestos', 'freefactu' ); ?></span>
                    <button type="button" class="freefactu-close-presupuesto-dialog freefactu-series-dialog__close">&times;</button>
                </h2>
                
                <form id="freefactu-presupuesto-series-form">
                    <!-- Live Preview (at the top) -->
                    <div id="freefactu-presupuesto-dialog-preview" class="freefactu-series-preview">
                        <div class="freefactu-series-preview__label">
                            <?php esc_html_e( 'Vista previa', 'freefactu' ); ?>
                        </div>
                        <div id="freefactu-presupuesto-preview-number" class="freefactu-series-preview__number">
                            0001
                        </div>
                    </div>
                    
                    <p>
                        <label for="freefactu-presupuesto-series-name"><strong><?php esc_html_e( 'Nombre de la serie', 'freefactu' ); ?></strong></label>
                        <input type="text" id="freefactu-presupuesto-series-name" name="name" class="regular-text freefactu-series-dialog__input" 
                               placeholder="<?php esc_attr_e( 'Ej: PRES 2025', 'freefactu' ); ?>" required>
                    </p>
                    
                    <p>
                        <label for="freefactu-presupuesto-series-prefix"><strong><?php esc_html_e( 'Prefijo', 'freefactu' ); ?></strong></label>
                        <input type="text" id="freefactu-presupuesto-series-prefix" name="prefix" class="regular-text freefactu-presupuesto-series-input freefactu-series-dialog__input" 
                               placeholder="<?php esc_attr_e( 'Ej: PRES-[year]-', 'freefactu' ); ?>">
                        <span class="description"><?php esc_html_e( 'Marcadores: [year], [month], [day]', 'freefactu' ); ?></span>
                    </p>
                    
                    <p>
                        <label for="freefactu-presupuesto-series-suffix"><strong><?php esc_html_e( 'Sufijo', 'freefactu' ); ?></strong></label>
                        <input type="text" id="freefactu-presupuesto-series-suffix" name="suffix" class="regular-text freefactu-presupuesto-series-input freefactu-series-dialog__input" 
                               placeholder="<?php esc_attr_e( 'Ej: -A', 'freefactu' ); ?>">
                    </p>
                    
                    <p>
                        <label for="freefactu-presupuesto-series-padding"><strong><?php esc_html_e( 'Relleno de ceros', 'freefactu' ); ?></strong></label>
                        <input type="number" id="freefactu-presupuesto-series-padding" name="padding" class="small-text freefactu-presupuesto-series-input freefactu-series-dialog__input" 
                               min="0" max="10" value="4">
                        <span class="description"><?php esc_html_e( '(ej: 4 â†’ 0001)', 'freefactu' ); ?></span>
                    </p>
                    
                    <div class="freefactu-series-dialog__footer">
                        <button type="submit" class="button button-primary">
                            <span class="dashicons dashicons-plus-alt2 freefactu-btn-icon"></span>
                            <?php esc_html_e( 'Crear Serie', 'freefactu' ); ?>
                        </button>
                    </div>
                </form>
            </div>
        </div>
        <?php
    }

    /**
     * Count total presupuestos.
     *
     * @return int Number of presupuestos.
     */
    private function count_presupuestos() {
        global $wpdb;
        $table_name = $wpdb->prefix . self::TABLE_NAME;
        
        // Check cache first for table existence
        $table_exists = wp_cache_get( 'freefactu_presupuestos_table_exists', 'freefactu' );
        
        if ( false === $table_exists ) {
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery
            $table_exists = $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) === $table_name;
            wp_cache_set( 'freefactu_presupuestos_table_exists', $table_exists, 'freefactu', DAY_IN_SECONDS );
        }

        if ( ! $table_exists ) {
             return 0;
        }
        
        // Check count cache
        $count = wp_cache_get( 'freefactu_presupuestos_count', 'freefactu_presupuestos' );
        
        if ( false === $count ) {
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery
            $count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM $table_name" );
            wp_cache_set( 'freefactu_presupuestos_count', $count, 'freefactu_presupuestos' );
        }
        
        return $count;
    }

    /**
     * AJAX handler for setting active series.
     */
    public function ajax_set_active_series() {
        check_ajax_referer( 'freefactu_presupuesto_series_nonce', 'security' );
        
        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array( 'message' => __( 'Permiso denegado.', 'freefactu' ) ) );
        }
        
        $series_id = isset( $_POST['series_id'] ) ? absint( $_POST['series_id'] ) : 0;
        
        if ( ! $series_id ) {
            wp_send_json_error( array( 'message' => __( 'ID de serie no válido.', 'freefactu' ) ) );
        }
        
        // Verify the series belongs to this extension
        $series = Freefactu_Extension_Series_Store::get_series( $series_id );
        if ( ! $series || $series->extension_id !== self::EXTENSION_ID ) {
            wp_send_json_error( array( 'message' => __( 'Serie no encontrada.', 'freefactu' ) ) );
        }
        
        $result = Freefactu_Extension_Series_Store::set_active_series( $series_id );
        
        if ( is_wp_error( $result ) ) {
            wp_send_json_error( array( 'message' => $result->get_error_message() ) );
        }
        
        wp_send_json_success( array( 'message' => __( 'Serie activa actualizada.', 'freefactu' ) ) );
    }

    /**
     * AJAX handler for creating series.
     */
    public function ajax_create_series() {
        check_ajax_referer( 'freefactu_presupuesto_series_nonce', 'security' );
        
        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array( 'message' => __( 'Permiso denegado.', 'freefactu' ) ) );
        }
        
        $name = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';
        
        if ( empty( $name ) ) {
            wp_send_json_error( array( 'message' => __( 'El nombre es requerido.', 'freefactu' ) ) );
        }
        
        $data = array(
            'name'    => $name,
            'prefix'  => isset( $_POST['prefix'] ) ? sanitize_text_field( wp_unslash( $_POST['prefix'] ) ) : '',
            'suffix'  => isset( $_POST['suffix'] ) ? sanitize_text_field( wp_unslash( $_POST['suffix'] ) ) : '',
            'padding' => isset( $_POST['padding'] ) ? absint( $_POST['padding'] ) : 4,
        );
        
        $result = Freefactu_Extension_Series_Store::create_series( self::EXTENSION_ID, $data );
        
        if ( is_wp_error( $result ) ) {
            wp_send_json_error( array( 'message' => $result->get_error_message() ) );
        }
        
        wp_send_json_success( array(
            'message'   => __( 'Serie creada correctamente.', 'freefactu' ),
            'series_id' => $result,
        ) );
    }

    /**
     * AJAX handler for deleting series.
     */
    public function ajax_delete_series() {
        check_ajax_referer( 'freefactu_presupuesto_series_nonce', 'security' );
        
        if ( ! current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array( 'message' => __( 'Permiso denegado.', 'freefactu' ) ) );
        }
        
        $series_id = isset( $_POST['series_id'] ) ? absint( $_POST['series_id'] ) : 0;
        
        if ( ! $series_id ) {
            wp_send_json_error( array( 'message' => __( 'ID de serie no válido.', 'freefactu' ) ) );
        }
        
        // Verify the series belongs to this extension
        $series = Freefactu_Extension_Series_Store::get_series( $series_id );
        if ( ! $series || $series->extension_id !== self::EXTENSION_ID ) {
            wp_send_json_error( array( 'message' => __( 'Serie no encontrada.', 'freefactu' ) ) );
        }
        
        $result = Freefactu_Extension_Series_Store::delete_series( $series_id );
        
        if ( is_wp_error( $result ) ) {
            wp_send_json_error( array( 'message' => $result->get_error_message() ) );
        }
        
        wp_send_json_success( array( 'message' => __( 'Serie eliminada correctamente.', 'freefactu' ) ) );
    }

    /**
     * Render settings section in Configuración tab.
     */
    public function render_settings_section() {
        if ( ! class_exists( 'Freefactu_Extensions' ) || 
             ! Freefactu_Extensions::is_extension_active( self::EXTENSION_ID ) ) {
            return;
        }

        $settings = self::get_settings();
        ?>
        <div class="freefactu-settings-section freefactu-extension-section">
            <h2>
                <span class="dashicons dashicons-media-document" style="margin-right: 5px; vertical-align: middle;"></span>
                <?php esc_html_e( 'Generación de Presupuestos', 'freefactu' ); ?>
                <span class="freefactu-extension-badge"><?php esc_html_e( 'Extensión', 'freefactu' ); ?></span>
            </h2>
            <p class="description freefactu-settings-section__description">
                <?php esc_html_e( 'Configura la generación de presupuestos para tus pedidos. Los presupuestos se pueden convertir fácilmente en facturas.', 'freefactu' ); ?>
            </p>

            <table class="form-table">
                <tr>
                    <th scope="row">
                        <label for="presupuesto_enabled">
                            <?php esc_html_e( 'Activar presupuestos', 'freefactu' ); ?>
                        </label>
                    </th>
                    <td>
                        <label>
                            <input type="checkbox" id="presupuesto_enabled" 
                                   name="<?php echo esc_attr( self::OPTION_KEY ); ?>[enabled]" value="1" 
                                   <?php checked( ! empty( $settings['enabled'] ) ); ?>>
                            <?php esc_html_e( 'Habilitar generación de presupuestos', 'freefactu' ); ?>
                        </label>
                    </td>
                </tr>
                <tr>
                    <th scope="row">
                        <?php esc_html_e( 'Formato de numeración', 'freefactu' ); ?>
                    </th>
                    <td>
                        <div class="freefactu-extension-form-gap">
                            <label>
                                <?php esc_html_e( 'Prefijo:', 'freefactu' ); ?>
                                <input type="text" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[prefix]" 
                                       value="<?php echo esc_attr( $settings['prefix'] ); ?>" class="small-text">
                            </label>
                            <label>
                                <?php esc_html_e( 'Próximo número:', 'freefactu' ); ?>
                                <input type="number" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[next_number]" 
                                       value="<?php echo esc_attr( $settings['next_number'] ); ?>" class="small-text" min="1">
                            </label>
                            <label>
                                <?php esc_html_e( 'Sufijo:', 'freefactu' ); ?>
                                <input type="text" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[suffix]" 
                                       value="<?php echo esc_attr( $settings['suffix'] ); ?>" class="small-text">
                            </label>
                            <label>
                                <?php esc_html_e( 'Dígitos:', 'freefactu' ); ?>
                                <input type="number" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[padding]" 
                                       value="<?php echo esc_attr( $settings['padding'] ); ?>" class="small-text" min="1" max="10">
                            </label>
                        </div>
                        <p class="description">
                            <?php 
                            $preview = $settings['prefix'] . str_pad( $settings['next_number'], $settings['padding'], '0', STR_PAD_LEFT ) . $settings['suffix'];
                            /* translators: %s: Preview string */
                            echo wp_kses_post( sprintf( __( 'Vista previa: %s', 'freefactu' ), '<code>' . esc_html( $preview ) . '</code>' ) ); 
                            ?>
                        </p>
                    </td>
                </tr>
                <tr>
                    <th scope="row">
                        <label for="presupuesto_validity_days">
                            <?php esc_html_e( 'Días de validez', 'freefactu' ); ?>
                        </label>
                    </th>
                    <td>
                        <input type="number" id="presupuesto_validity_days" 
                               name="<?php echo esc_attr( self::OPTION_KEY ); ?>[validity_days]" 
                               value="<?php echo esc_attr( $settings['validity_days'] ); ?>" class="small-text" min="1">
                        <span><?php esc_html_e( 'días', 'freefactu' ); ?></span>
                        <p class="description">
                            <?php esc_html_e( 'Número de días que el presupuesto será válido desde su creación.', 'freefactu' ); ?>
                        </p>
                    </td>
                </tr>
                <tr>
                    <th scope="row">
                        <label for="presupuesto_show_validity">
                            <?php esc_html_e( 'Mostrar fecha de validez', 'freefactu' ); ?>
                        </label>
                    </th>
                    <td>
                        <label>
                            <input type="checkbox" id="presupuesto_show_validity" 
                                   name="<?php echo esc_attr( self::OPTION_KEY ); ?>[show_validity_date]" value="1" 
                                   <?php checked( ! empty( $settings['show_validity_date'] ) ); ?>>
                            <?php esc_html_e( 'Mostrar fecha de validez en el PDF', 'freefactu' ); ?>
                        </label>
                    </td>
                </tr>
                <tr>
                    <th scope="row">
                        <label for="presupuesto_pdf_title">
                            <?php esc_html_e( 'Título del PDF', 'freefactu' ); ?>
                        </label>
                    </th>
                    <td>
                        <input type="text" id="presupuesto_pdf_title" 
                               name="<?php echo esc_attr( self::OPTION_KEY ); ?>[pdf_title]" 
                               value="<?php echo esc_attr( $settings['pdf_title'] ); ?>" class="regular-text">
                        <p class="description">
                            <?php esc_html_e( 'Título que aparece en la cabecera del PDF (ej: Presupuesto, Cotización, Oferta).', 'freefactu' ); ?>
                        </p>
                    </td>
                </tr>
                <tr>
                    <th scope="row">
                        <label for="presupuesto_pdf_footer">
                            <?php esc_html_e( 'Texto del pie de página', 'freefactu' ); ?>
                        </label>
                    </th>
                    <td>
                        <input type="text" id="presupuesto_pdf_footer" 
                               name="<?php echo esc_attr( self::OPTION_KEY ); ?>[pdf_footer_text]" 
                               value="<?php echo esc_attr( $settings['pdf_footer_text'] ); ?>" class="large-text">
                        <p class="description">
                            <?php esc_html_e( 'Usa {validity_days} para mostrar los días de validez.', 'freefactu' ); ?>
                        </p>
                    </td>
                </tr>
            </table>
        </div>
        <?php
    }

    /**
     * Check if extension is properly activated.
     *
     * @return bool True if extension should be active.
     */
    public static function is_active() {
        if ( ! class_exists( 'Freefactu_Extensions' ) ) {
            return false;
        }
        return Freefactu_Extensions::is_extension_active( self::EXTENSION_ID );
    }
}

// Initialize the extension only if active
if ( class_exists( 'Freefactu_Extensions' ) && Freefactu_Extensions::is_extension_active( 'presupuestos' ) ) {
    Freefactu_Presupuestos::instance();
}
