<?php

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

use Freefactu_Vendor\Endroid\QrCode\Builder\Builder;
use Freefactu_Vendor\Endroid\QrCode\Encoding\Encoding;
use Freefactu_Vendor\Endroid\QrCode\ErrorCorrectionLevel;
use Freefactu_Vendor\Endroid\QrCode\RoundBlockSizeMode;
use Freefactu_Vendor\Endroid\QrCode\Writer\PngWriter;

class Freefactu_History {

    /**
     * Constructor - initializes history class.
     *
     * What this function does:
     * - Registers admin_post action for debug invoice handler
     * - Menu registration handled by Admin class
     *
     * Where it's called from:
     * - freefactu.php: __construct() method during plugin initialization
     *
     * @return void
     */
    public function __construct() {
        // No longer adding menu here
        add_action( 'admin_post_freefactu_debug_invoice', array( $this, 'handle_debug_invoice' ) );
        
        // AJAX handler for debug modal content
        add_action( 'wp_ajax_freefactu_get_debug_content', array( $this, 'ajax_get_debug_content' ) );
    }

    /**
     * AJAX handler to get debug invoice content for modal display.
     *
     * What this function does:
     * - Verifies user permissions and nonce
     * - Retrieves invoice and order data
     * - Returns debug content HTML via AJAX
     * - Content is loaded into a modal instead of a separate page
     *
     * Where it's called from:
     * - JavaScript: AJAX call from debug button click
     *
     * @return void (outputs JSON and exits)
     */
    public function ajax_get_debug_content() {
        // Verify nonce
        if ( ! check_ajax_referer( 'freefactu_debug_invoice', 'security', false ) ) {
            wp_send_json_error( __( 'Error de seguridad. Por favor, recarga la página.', 'freefactu' ) );
        }

        // Verify permissions
        if ( ! current_user_can( 'manage_verifactu' ) ) {
            wp_send_json_error( __( 'No tienes permisos suficientes para ver esta información.', 'freefactu' ) );
        }

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

        // Get invoice from database
        $invoice_db = Freefactu_DB::get_invoice_by_order_id( $order_id );
        if ( ! $invoice_db ) {
            wp_send_json_error( __( 'Factura no encontrada.', 'freefactu' ) );
        }

        // Try to get order (may be null if deleted)
        $order = wc_get_order( $order_id );
        $order_exists = $order ? true : false;

        // Get all debug data
        $options = get_option( 'freefactu_settings' );

        // Check AEAT status - always use database
        $csv = $invoice_db->csv;
        $sent_to_aeat = ! empty( $csv );

        // Check QR status
        $company_nif = isset( $options['company_nif'] ) ? $options['company_nif'] : '';
        $env = isset( $options['environment'] ) ? $options['environment'] : 'test';
        $base_url = ( $env === 'production' ) ? 'https://www2.agenciatributaria.gob.es/wlpl/TIKE-CONT/ValidarQR?' : 'https://prewww2.aeat.es/wlpl/TIKE-CONT/ValidarQR?';

        // Get invoice data from database
        $invoice_number = $invoice_db->invoice_number;
        $invoice_date = $invoice_db->invoice_date;
        $invoice_total = $invoice_db->total;

        // Handle invoice date - could be timestamp or date string
        if ( is_numeric( $invoice_date ) ) {
            $invoice_date_formatted = date_i18n( 'd-m-Y', $invoice_date );
        } elseif ( ! empty( $invoice_date ) ) {
            $invoice_date_formatted = date_i18n( 'd-m-Y', strtotime( $invoice_date ) );
        } else {
            $invoice_date_formatted = date_i18n( 'd-m-Y' );
        }

        $params = array(
            'nif' => $company_nif,
            'numserie' => $invoice_number ? $invoice_number : $order_id,
            'fecha' => $invoice_date_formatted,
            'importe' => number_format( $invoice_total, 2, '.', '' ),
        );
        $qr_url = $base_url . http_build_query( $params );
        $cache_key = 'freefactu_qr_v2_' . md5( $qr_url . 150 );
        $qr_cached = get_transient( $cache_key );

        // QR is "created" if we have CSV (can be generated on-demand) or if it's already cached
        $qr_can_be_created = ! empty( $csv );
        $qr_is_cached = $qr_cached !== false;

        // Check PDF status - use database
        $pdf_path = $invoice_db->pdf_path;
        // Convert stored relative path to absolute for file existence check
        $absolute_pdf_path = Freefactu_Filesystem::to_absolute_path( $pdf_path );
        $pdf_exists = ! empty( $pdf_path ) && Freefactu_Filesystem::exists( $absolute_pdf_path );

        // Capture the modal content HTML
        ob_start();
        include FREEFACTU_PLUGIN_DIR . 'includes/admin/views/debug-modal-content.php';
        $html = ob_get_clean();

        wp_send_json_success( array( 'html' => $html ) );
    }

	/**
	 * Render the invoice history page.
	 *
	 * What this function does:
	 * - Prepares data for the invoice list view
	 * - Handles filtering and pagination
	 * - Includes the history-page.php view template
	 *
	 * Where it's called from:
	 * - class-freefactu-admin.php: render_main_page() method when facturas tab is active
	 *
	 * @return void
	 */
	public static function render_history_page() {
		// Get filter values from URL
		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		$filter_date_from = isset( $_GET['filter_date_from'] ) ? sanitize_text_field( wp_unslash( $_GET['filter_date_from'] ) ) : '';
		$filter_date_to   = isset( $_GET['filter_date_to'] ) ? sanitize_text_field( wp_unslash( $_GET['filter_date_to'] ) ) : '';
		$filter_status    = isset( $_GET['filter_status'] ) ? sanitize_text_field( wp_unslash( $_GET['filter_status'] ) ) : '';
		// phpcs:enable
		
		$filters = array();
		if ( $filter_date_from ) {
			$filters['date_from'] = $filter_date_from;
		}
		if ( $filter_date_to ) {
			$filters['date_to'] = $filter_date_to;
		}
		if ( $filter_status ) {
			$filters['status'] = $filter_status;
		}
		
		$has_filters = ! empty( $filters );
		
		// Pagination
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$paged  = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1;
		$limit  = 20;
		$offset = ( $paged - 1 ) * $limit;

		// Get invoices with or without filters
		if ( $has_filters ) {
			$invoices       = Freefactu_DB::get_invoices_filtered( $filters, $limit, $offset );
			$total_invoices = Freefactu_DB::count_invoices_filtered( $filters );
		} else {
			$invoices       = Freefactu_DB::get_invoices( $limit, $offset );
			$total_invoices = Freefactu_DB::count_invoices();
		}
		$total_pages = ceil( $total_invoices / $limit );

		// Include the view template
		include FREEFACTU_PLUGIN_DIR . 'includes/admin/views/history-page.php';
	}

    /**
     * Validate that a string is a safe data URI for PNG images.
     *
     * What this function does:
     * - Checks if string starts with 'data:image/png;base64,'
     * - Validates base64 part contains only valid characters
     * - Prevents XSS attacks via malicious data URIs
     * - Returns true if safe, false otherwise
     *
     * Where it's called from:
     * - class-freefactu-history.php: render_history_page() method
     *
     * @param string $data_uri The data URI to validate.
     * @return bool True if valid and safe, false otherwise.
     */
    public static function is_valid_data_uri( $data_uri ) {
        // Must start with data:image/png;base64,
        if ( strpos( $data_uri, 'data:image/png;base64,' ) !== 0 ) {
            return false;
        }

        // Extract base64 part
        $base64_part = substr( $data_uri, 22 ); // Length of "data:image/png;base64,"

        // Validate base64 format (only valid base64 characters)
        if ( ! preg_match( '/^[A-Za-z0-9+\/=]+$/', $base64_part ) ) {
            return false;
        }

        return true;
    }

    /**
     * Generate QR code as base64 data URI.
     *
     * What this function does:
     * - Generates QR code using endroid/qr-code library
     * - Caches result in transients (30 days)
     * - Returns base64 encoded PNG image
     * - Uses v2 cache key to invalidate old external API cache
     * - Returns empty string on failure
     *
     * Where it's called from:
     * - class-freefactu-history.php: render_history_page() method
     *
     * @param string $url URL to encode in QR code.
     * @param int    $size QR code size in pixels (default: 70).
     * @return string Base64 data URI or empty string on failure.
     */
    public static function generate_qr_code_base64( $url, $size = 70 ) {
        if ( empty( $url ) ) {
            return '';
        }

        // Check cache first (v2 to invalidate old external API cache)
        $cache_key = 'freefactu_qr_v2_' . md5( $url . $size );
        $cached = get_transient( $cache_key );

        if ( $cached !== false && strpos( $cached, 'data:image/png;base64,' ) === 0 ) {
            return $cached;
        }

        // Check if QR library is available
        if ( ! class_exists( 'Freefactu_Vendor\\Endroid\\QrCode\\Builder\\Builder' ) ) {
            if ( class_exists( 'Freefactu_Logger' ) ) {
                Freefactu_Logger::log( 'QR Code library not loaded', 'error' );
            }
            return '';
        }

        try {
            // Generate QR code using endroid/qr-code library (v6 uses named constructor args)
            $builder = new Builder(
                writer: new PngWriter(),
                data: $url,
                encoding: new Encoding( 'UTF-8' ),
                errorCorrectionLevel: ErrorCorrectionLevel::Low,
                size: $size,
                margin: 0,
                roundBlockSizeMode: RoundBlockSizeMode::Enlarge,
            );
            $result = $builder->build();

            // Convert to base64 using built-in getDataUri()
            $base64 = $result->getDataUri();

            // Cache for 30 days (QR content doesn't change)
            set_transient( $cache_key, $base64, 30 * DAY_IN_SECONDS );

            return $base64;

        } catch ( \Throwable $e ) {
            if ( class_exists( 'Freefactu_Logger' ) ) {
                Freefactu_Logger::log( 'QR Code Generation Error: ' . $e->getMessage(), 'error' );
            }
            return '';
        }
    }

    /**
     * Handle debug invoice request - displays all debug information for an order.
     *
     * What this function does:
     * - Verifies user permissions and nonce
     * - Retrieves invoice and order data
     * - Displays comprehensive debug information:
     *   - Operation status (AEAT, QR, PDF, snapshot)
     *   - Invoice data (number, date, total, CSV, hash)
     *   - Order data (if order exists)
     *   - Error messages if any
     * - Shows snapshot information and size
     * - Provides back link to invoice list
     * - Handles deleted orders gracefully
     *
     * Where it's called from:
     * - WordPress: admin_post_freefactu_debug_invoice action hook
     * - Triggered when admin clicks debug icon in invoice list
     *
     * @return void
     */
    public function handle_debug_invoice() {
        if ( ! current_user_can( 'manage_verifactu' ) ) {
            wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'freefactu' ) );
        }

        check_admin_referer( 'freefactu_debug_invoice' );

        $order_id = isset( $_GET['order_id'] ) ? intval( $_GET['order_id'] ) : 0;
        if ( ! $order_id ) {
            wp_die( esc_html__( 'Invalid order ID.', 'freefactu' ) );
        }

        // Get invoice from database
        $invoice_db = Freefactu_DB::get_invoice_by_order_id( $order_id );
        if ( ! $invoice_db ) {
            wp_die( esc_html__( 'Factura no encontrada.', 'freefactu' ) );
        }

        // Try to get order (may be null if deleted)
        $order = wc_get_order( $order_id );
        $order_exists = $order ? true : false;

        // Get all debug data
        $options = get_option( 'freefactu_settings' );

        // Check AEAT status - always use database
        $csv = $invoice_db->csv;
        $sent_to_aeat = ! empty( $csv );

        // Check QR status
        // QR can be created if we have CSV from AEAT (it's generated on-demand)
        // We check both if it's cached AND if it can be created
        $company_nif = isset( $options['company_nif'] ) ? $options['company_nif'] : '';
        $env = isset( $options['environment'] ) ? $options['environment'] : 'test';
        $base_url = ( $env === 'production' ) ? 'https://www2.agenciatributaria.gob.es/wlpl/TIKE-CONT/ValidarQR?' : 'https://prewww2.aeat.es/wlpl/TIKE-CONT/ValidarQR?';

        // Get invoice data from database
        $invoice_number = $invoice_db->invoice_number;
        $invoice_date = $invoice_db->invoice_date;
        $invoice_total = $invoice_db->total;

        // Handle invoice date - could be timestamp or date string
        if ( is_numeric( $invoice_date ) ) {
            $invoice_date_formatted = date_i18n( 'd-m-Y', $invoice_date );
        } elseif ( ! empty( $invoice_date ) ) {
            $invoice_date_formatted = date_i18n( 'd-m-Y', strtotime( $invoice_date ) );
        } else {
            $invoice_date_formatted = date_i18n( 'd-m-Y' );
        }

        $params = array(
            'nif' => $company_nif,
            'numserie' => $invoice_number ? $invoice_number : $order_id,
            'fecha' => $invoice_date_formatted,
            'importe' => number_format( $invoice_total, 2, '.', '' ),
        );
        $qr_url = $base_url . http_build_query( $params );
        $cache_key = 'freefactu_qr_v2_' . md5( $qr_url . 150 );
        $qr_cached = get_transient( $cache_key );

        // QR is "created" if we have CSV (can be generated on-demand) or if it's already cached
        $qr_can_be_created = ! empty( $csv );
        $qr_is_cached = $qr_cached !== false;

        // Check PDF status - use database
        $pdf_path = $invoice_db->pdf_path;
        // Convert stored relative path to absolute for file existence check
        $absolute_pdf_path = Freefactu_Filesystem::to_absolute_path( $pdf_path );
        $pdf_exists = ! empty( $pdf_path ) && Freefactu_Filesystem::exists( $absolute_pdf_path );

        // Include the debug page view template
        include FREEFACTU_PLUGIN_DIR . 'includes/admin/views/debug-invoice-page.php';
        exit;
    }
    /**
     * Format and highlight XML string for display.
     *
     * SECURITY NOTE: This function is safe for output because:
     * 1. The raw XML is first escaped using htmlspecialchars() at line 402
     * 2. Only hardcoded, static span tags with class names are added for highlighting
     * 3. The output contains no user-controlled HTML attributes
     * 4. The CSS classes (xml-tag, xml-attr-name, etc.) are hardcoded strings
     *
     * @param string $xml Raw XML string.
     * @return string Safely escaped HTML with syntax highlighting spans.
     */
    public static function format_and_highlight_xml( $xml ) {
        if ( empty( $xml ) ) return '';

        // 1. Pretty Print using DOMDocument
        $dom = new DOMDocument();
        $dom->preserveWhiteSpace = false;
        $dom->formatOutput = true;
        // Suppress errors for malformed XML
        $loaded = @$dom->loadXML( $xml );
        
        if ( $loaded ) {
            $formatted_xml = $dom->saveXML();
        } else {
            // Fallback for invalid XML
            $formatted_xml = $xml;
        }

        // 2. Syntax Highlighting
        // Escape HTML entities to prevent execution and allow safe display
        $formatted_xml = htmlspecialchars( $formatted_xml );

        // Apply colors using regex replacement
        // Order is important
        
        // 1. Strings/Attribute Values (Blue/Green)
        $formatted_xml = preg_replace( '/(&quot;.*?&quot;)/s', '<span class="xml-attr-val">$1</span>', $formatted_xml );
        
        // 2. Attribute Names (Orange) - Word before =
        $formatted_xml = preg_replace( '/(\s)([a-zA-Z0-9:-]+)(=)/', '$1<span class="xml-attr-name">$2</span>$3', $formatted_xml );
        
        // 3. Opening/Closing Tags (Red)
        $formatted_xml = preg_replace( '/(&lt;\/?[a-zA-Z0-9:-]+)/', '<span class="xml-tag">$1</span>', $formatted_xml );
        
        // 4. Tag Ends > (Red)
        $formatted_xml = str_replace( array( '&gt;', '?&gt;' ), array( '<span class="xml-tag">&gt;</span>', '<span class="xml-tag">?&gt;</span>' ), $formatted_xml );
        
        // 5. Comments (Grey) - Clean up any coloring matches inside comments
        $formatted_xml = preg_replace_callback(
            '/(&lt;!--.*?--&gt;)/s', 
            function( $m ) { return '<span class="xml-comment">' . wp_strip_all_tags( $m[1] ) . '</span>'; }, 
            $formatted_xml
        );
        
        return '<div class="xml-view">' . $formatted_xml . '</div>';
    }
}
