<?php
namespace auctionforge\inc\api;

use auctionforge\inc\helpers\SettingsHelper;
use auctionforge\inc\BidSpiritRequest;

/**
 * Generates PDF invoices by fetching the Bidspirit standaloneScene payment page
 * and converting it to a downloadable PDF using Dompdf.
 */
class InvoicePdfGenerator {

    /**
     * Register the AJAX handlers for logged-in and non-logged-in users.
     */
    public static function init() {
        add_action('wp_ajax_af_download_invoice_pdf', [self::class, 'handle_download']);
        add_action('wp_ajax_nopriv_af_download_invoice_pdf', [self::class, 'handle_download']);
        
        add_action('wp_ajax_af_resolve_bill_titles', [self::class, 'resolve_bill_titles']);
        add_action('wp_ajax_nopriv_af_resolve_bill_titles', [self::class, 'resolve_bill_titles']);
    }

    /**
     * Handle the PDF download request.
     */
    public static function handle_download() {
        // Verify nonce
        check_ajax_referer('bp-ajax-string', 'security');

        $bill_key = isset($_GET['bill_key']) ? sanitize_text_field($_GET['bill_key']) : '';
        $bill_desc = isset($_GET['bill_desc']) ? sanitize_text_field($_GET['bill_desc']) : 'Invoice';
        $bill_status = isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '';

        if (empty($bill_key)) {
            wp_die('Missing bill key.', 'Error', ['response' => 400]);
        }

        $bidspirit_server = SettingsHelper::getOption('server', '');

        if (empty($bidspirit_server)) {
            wp_die('BidSpirit server not configured.', 'Error', ['response' => 500]);
        }

        // Build the API URL for JSON bill content
        $api_url = rtrim($bidspirit_server, '/') . '/api/standalone/payments/getBillContent.api';

        // Fetch the HTML through the Bidspirit API
        $response = wp_remote_post($api_url, [
            'timeout' => 30,
            'sslverify' => true,
            'body' => [
                'billKey' => $bill_key
            ],
            'headers' => [
                'Accept' => 'application/json, text/plain, */*',
                'User-Agent' => 'AuctionForge/3.2.7.0 WordPress InvoicePDF',
            ],
        ]);

        if (is_wp_error($response)) {
            wp_die('Failed to fetch invoice: ' . $response->get_error_message(), 'Error', ['response' => 502]);
        }

        $status_code = wp_remote_retrieve_response_code($response);
        if ($status_code !== 200) {
            wp_die('Bidspirit returned HTTP ' . $status_code, 'Error', ['response' => $status_code]);
        }

        $json_res = json_decode(wp_remote_retrieve_body($response), true);
        
        if (!empty($json_res['errorType'])) {
            wp_die('Bidspirit API Error: ' . (isset($json_res['message']) ? $json_res['message'] : 'Unknown error'), 'Error', ['response' => 500]);
        }

        $html_content = isset($json_res['response']) ? $json_res['response'] : '';

        // Fetch the Breakdown through the Bidspirit API to ensure Taxes, Shipping and final Totals are included
        $breakdown_url = rtrim($bidspirit_server, '/') . '/api/standalone/payments/getBillBreakdown.api';
        $response_breakdown = wp_remote_post($breakdown_url, [
            'timeout' => 30,
            'sslverify' => true,
            'body' => [
                'billKey' => $bill_key
            ],
            'headers' => [
                'Accept' => 'application/json, text/plain, */*',
                'User-Agent' => 'AuctionForge/3.2.7.0 WordPress InvoicePDF',
            ],
        ]);

        $html_breakdown = '';
        if (!is_wp_error($response_breakdown) && wp_remote_retrieve_response_code($response_breakdown) === 200) {
            $json_breakdown = json_decode(wp_remote_retrieve_body($response_breakdown), true);
            if (isset($json_breakdown['response'])) {
                $html_breakdown = $json_breakdown['response'];
            }
        }

        // --- Data Extraction ---
        $data = self::extract_all_invoice_data($html_content, $html_breakdown);
        
        // Status priority:
        // 1. Frontend status from profile template (bill.isPaid) — most reliable
        // 2. "Bill paid" indicator in the API HTML response
        // 3. statusCell extraction from getBillContent.api (least reliable, often stale)
        if (!empty($bill_status)) {
            $data['bill']['status'] = $bill_status;
        } elseif (preg_match('/Bill paid/i', $html_content)) {
            $data['bill']['status'] = 'Paid';
        }

        // Construct the professional PDF document
        $clean_html = self::build_professional_template($data);

        // Generate the PDF
        self::generate_pdf($clean_html, $bill_desc);
    }

    /**
     * AJAX handler to resolve auction codes to professional titles.
     * Accepts either a 'code' (auction number) or a 'bill_key' (to fetch from API).
     */
    public static function resolve_bill_titles() {
        check_ajax_referer('bp-ajax-string', 'security');
        
        $lookups = isset($_POST['lookups']) ? (array)$_POST['lookups'] : [];
        $resolved = [];
        
        foreach ($lookups as $id => $item) {
            $code = $item['code'] ?? '';
            $date = $item['date'] ?? '';
            
            if (!empty($code)) {
                // Direct code lookup (e.g., "C-123" from "Bill for auction C-123...")
                $resolved[$id] = self::find_auction_name_by_code($code, $date);
            } elseif (!empty($date)) {
                // No code available — match by date against synced auction data
                $resolved[$id] = self::find_auction_name_by_date($date);
            }
        }
        
        wp_send_json_success($resolved);
    }

    /**
     * Find an auction title by matching its date against synced WordPress auction data.
     * @param string $date Date string like 'Mar 29, 2026'
     * @return string Resolved auction name or empty string
     */
    private static function find_auction_name_by_date($date) {
        if (empty($date)) return '';
        
        $target_ts = strtotime($date);
        if (!$target_ts) return '';
        
        $target_date = date('Y-m-d', $target_ts);
        
        // Get all auction terms with synced auction data
        $terms = get_terms([
            'taxonomy' => 'auction_number',
            'hide_empty' => false,
        ]);
        
        if (is_wp_error($terms) || empty($terms)) return '';
        
        foreach ($terms as $term) {
            // Check auction_days meta for date matching
            $auction_days = SettingsHelper::getTermOption($term->term_id, 'auction_days');
            if (!empty($auction_days) && is_array($auction_days)) {
                foreach ($auction_days as $day) {
                    $day_date = '';
                    if (!empty($day->date)) {
                        $day_date = date('Y-m-d', strtotime($day->date));
                    } elseif (!empty($day->auctionStarted)) {
                        $day_date = date('Y-m-d', strtotime($day->auctionStarted));
                    }
                    
                    if ($day_date === $target_date) {
                        // Found a matching auction — resolve the title
                        $resolved_name = '';
                        $bs_auction_id = SettingsHelper::getTermOption($term->term_id, 'auction_id');
                        if ($bs_auction_id) {
                            $api_res = BidSpiritRequest::send('auctions/getAuctionInfo.api', [
                                'auctionId' => intval($bs_auction_id),
                                'language'  => SettingsHelper::getOption('lang', 'en')
                            ]);
                            if ($api_res['response']) {
                                $info = json_decode($api_res['response'], true);
                                if (isset($info['response']['mainLangName']) && !empty($info['response']['mainLangName'])) {
                                    $resolved_name = $info['response']['mainLangName'];
                                } elseif (isset($info['response']['name'])) {
                                    $resolved_name = $info['response']['name'];
                                }
                            }
                        }
                        // Fallback to term name
                        if (empty($resolved_name)) {
                            $resolved_name = $term->name;
                        }
                        return $resolved_name;
                    }
                }
            }
        }
        
        return '';
    }

    /**
     * Fetch bill HTML via getBillContent.api and extract the auction code + date.
     * @param string $bill_key The bill key for the API call
     * @return array|null ['code' => 'C-123', 'date' => 'Mar 29, 2026'] or null
     */
    private static function extract_auction_code_from_bill($bill_key) {
        $bidspirit_server = SettingsHelper::getOption('server', '');
        if (empty($bidspirit_server)) return null;
        
        $api_url = rtrim($bidspirit_server, '/') . '/api/standalone/payments/getBillContent.api';
        $response = wp_remote_post($api_url, [
            'timeout' => 15,
            'sslverify' => true,
            'body' => ['billKey' => $bill_key],
            'headers' => [
                'Accept' => 'application/json, text/plain, */*',
                'User-Agent' => 'AuctionForge/' . AUCTIONFORGE_VERSION . ' WordPress BillResolve',
            ],
        ]);
        
        if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) return null;
        
        $json = json_decode(wp_remote_retrieve_body($response), true);
        $html = $json['response'] ?? '';
        if (empty($html)) return null;
        
        // Extract auction code from the bill details table
        // Pattern in HTML: <td>Auction:&nbsp;</td> ... <td>...<div dir="ltr"> #C-123, Mar 29, 2026 </div></td>
        if (preg_match('/Auction:.*?<td[^>]*>.*?#([a-zA-Z0-9-]+)(?:,\s*([^<]+))?/si', $html, $m)) {
            $code = $m[1];
            $date = isset($m[2]) ? trim($m[2]) : '';
            return ['code' => $code, 'date' => $date];
        }
        
        return null;
    }

    /**
     * Map internal code like 'ai4' to professional name from WP/API.
     * @param string $code Auction code like '002'
     * @param string $date Optional date like 'Jun 27, 2026'
     */
    private static function find_auction_name_by_code($code, $date = '') {
        if (empty($code)) return '';
        
        global $wpdb;
        // Search for all terms with this auction_number meta
        $term_ids = $wpdb->get_col($wpdb->prepare(
            "SELECT term_id FROM {$wpdb->termmeta} WHERE meta_key = 'auction_number' AND meta_value = %s",
            $code
        ));

        if (empty($term_ids)) return '';

        $resolved_term_id = $term_ids[0]; // Default to first match

        // If multiple matches, try to narrow down by date
        if (count($term_ids) > 1 && !empty($date)) {
            foreach ($term_ids as $tid) {
                $auction_date_meta = get_term_meta($tid, 'auction_date', true);
                if (empty($auction_date_meta)) {
                    // Try to find a linked post if term doesn't have the date directly
                    $post_id = $wpdb->get_var($wpdb->prepare(
                        "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = 'auction_id' AND meta_value = %s LIMIT 1",
                        get_term_meta($tid, 'auction_id', true)
                    ));
                    if ($post_id) {
                        $auction_date_meta = get_post_meta($post_id, 'auction_date', true);
                    }
                }
                
                if (!empty($auction_date_meta)) {
                    // Simple fuzzy date check
                    $formatted_date = date('M j, Y', strtotime($date));
                    $meta_formatted = date('M j, Y', strtotime($auction_date_meta));
                    if ($formatted_date === $meta_formatted) {
                        $resolved_term_id = $tid;
                        break;
                    }
                }
            }
        }

        // Fetch from API for most current name (mainLangName)
        $resolved_name = '';
        $bs_auction_id = SettingsHelper::getTermOption($resolved_term_id, 'auction_id');
        if ($bs_auction_id) {
            $api_res = BidSpiritRequest::send('auctions/getAuctionInfo.api', [
                'auctionId' => intval($bs_auction_id),
                'language'  => SettingsHelper::getOption('lang', 'en')
            ]);

            if ($api_res['response']) {
                $item = json_decode($api_res['response'], true);
                if (isset($item['response']['mainLangName']) && !empty($item['response']['mainLangName'])) {
                    $resolved_name = $item['response']['mainLangName'];
                } elseif (isset($item['response']['name'])) {
                    $resolved_name = $item['response']['name'];
                }
            }
        }
        
        // Fallback to term name if API fails
        if (empty($resolved_name)) {
            $term = get_term($resolved_term_id, 'auction_number');
            if ($term && !is_wp_error($term)) {
                $resolved_name = $term->name;
            }
        }

        if (!empty($resolved_name)) {
            // Remove the auction code/ID from the name if it's there (e.g. "Title - 002" -> "Title")
            // We strip hyphenated matches of the code at the end
            $resolved_name = preg_replace('/\s*-\s*' . preg_quote($code, '/') . '\s*$/i', '', $resolved_name); 
            // Also strip "Number: 002" or similar patterns if BidSpirit injects them
            $resolved_name = preg_replace('/\s*#?' . preg_quote($code, '/') . '\b\s*/i', '', $resolved_name);
            $resolved_name = trim($resolved_name, " -");
        }
        
        return $resolved_name;
    }

    /**
     * Extracts structured data from Bidspirit HTML blobs using regex.
     */
    private static function extract_all_invoice_data($html_main, $html_breakdown) {
        $data = [
            'logo' => '',
            'house' => ['name' => SettingsHelper::getOption('house_name', ''), 'details' => ''],
            'customer' => ['name' => '', 'address' => '', 'email' => '', 'phone' => ''],
            'bill' => ['date' => '', 'number' => '', 'auction' => '', 'status' => ''],
            'items' => [],
            'totals' => [],
            'tax_label' => 'VAT' // default, will be detected below
        ];

        // Detect tax type from BidSpirit HTML: "Sales tax" vs "VAT"
        // BidSpirit uses "Sales tax" for US auction houses and "VAT" for European ones
        if (stripos($html_main, 'Sales tax') !== false) {
            $data['tax_label'] = 'Sales Tax';
        } elseif (stripos($html_breakdown, 'Sales tax') !== false) {
            $data['tax_label'] = 'Sales Tax';
        }

        // 1. Extract Logo
        if (preg_match('/<img[^>]*src="([^"]+)"/', $html_main, $m)) {
            $data['logo'] = $m[1];
        }

        // 2. Extract House Name/Phone (from the top bar)
        if (preg_match('/<td[^>]*style="float:right;"[^>]*>(.*?)<\/td>/si', $html_main, $m)) {
            $details = strip_tags($m[1], '<br><div>');
            $lines = preg_split('/<br>|<div>|<\/div>/i', $details, -1, PREG_SPLIT_NO_EMPTY);
            $data['house']['name'] = trim(strip_tags($lines[0] ?? $data['house']['name']));
            $data['house']['details'] = implode("\n", array_map('trim', array_map('strip_tags', array_slice($lines, 1))));
        }

        // 3. Extract Customer Info (To column)
        if (preg_match('/<td[^>]*min-width:\s*50%;[^>]*>(.*?)<\/td>/si', $html_main, $m)) {
            $content = $m[1];
            if (preg_match('/<div dir="ltr">(.*?)<\/div>/si', $content, $m2)) {
                $addr_parts = explode('<br />', $m2[1]);
                $data['customer']['name'] = trim(strip_tags($addr_parts[0]));
                $data['customer']['address'] = implode("\n", array_map('trim', array_map('strip_tags', array_slice($addr_parts, 1))));
            }
            if (preg_match('/alec@bidspirit\.com|[\w\.-]+@[\w\.-]+\.\w+/i', $content, $m_email)) {
                $data['customer']['email'] = $m_email[0];
            }
            if (preg_match('/\+\(\d+\)[\d\s-]+/i', $content, $m_phone)) {
                $data['customer']['phone'] = $m_phone[0];
            }
        }

        // 4. Extract Bill Meta
        if (preg_match('/(?:Invoice|Bill) date:&nbsp;<\/td>\s*<td>(.*?)<\/td>/i', $html_main, $m)) $data['bill']['date'] = trim($m[1]);
        if (preg_match('/Auction:&nbsp;<\/td>\s*<td>.*?<div dir="ltr">(.*?)<\/div>/si', $html_main, $m)) {
            $raw_auction = trim(strip_tags($m[1]));
            $data['bill']['auction'] = $raw_auction;

            // Mapping: Extract code like 'ai4' or 'C-123' and date from '#C-123, Jan 17, 2026'
            if (preg_match('/#([a-zA-Z0-9-]+)(?:,\s*(.*))?/', $raw_auction, $m_code)) {
                $code = $m_code[1];
                $date_part = isset($m_code[2]) ? trim($m_code[2]) : '';
                
                $resolved_name = self::find_auction_name_by_code($code, $date_part);
                if (!empty($resolved_name)) {
                    $data['bill']['auction'] = $resolved_name . ($date_part ? " - " . $date_part : "");
                }
            }
        }
        if (preg_match('/Customer number:&nbsp;<\/td>\s*<td>(.*?)<\/td>/i', $html_main, $m)) $data['bill']['number'] = trim($m[1]);
        if (preg_match('/bs-info="statusCell"[^>]*>(.*?)<\/td>/si', $html_main, $m)) $data['bill']['status'] = trim(strip_tags($m[1]));

        // 5. Extract Items and Totals from breakdown
        // Breakdown response usually contains two tables: [0] = items, [1] = totals
        $tables = explode('</table>', $html_breakdown);
        
        // Parse Items Table
        if (isset($tables[0]) && preg_match('/<table[^>]*>(.*?)<\/table>/si', $tables[0] . '</table>', $m_table)) {
            $rows = explode('</tr>', $m_table[1]);
            foreach ($rows as $row) {
                // Skip header row or empty lines
                if (stripos($row, 'LOT') !== false && stripos($row, 'Description') !== false) continue;
                if (empty(trim(strip_tags($row)))) continue;
                
                if (preg_match_all('/<t[hd][^>]*>(.*?)<\/t[hd]>/si', $row, $cells)) {
                    if (count($cells[1]) >= 3) {
                        $data['items'][] = [
                            'lot' => trim(strip_tags($cells[1][0])),
                            'desc' => trim(strip_tags($cells[1][1])),
                            'price' => trim(strip_tags($cells[1][2])),
                            'premium' => trim(strip_tags($cells[1][3] ?? ''))
                        ];
                    }
                }
            }
        }

        // Parse Totals Table
        if (isset($tables[1]) && preg_match('/<table[^>]*>(.*?)<\/table>/si', $tables[1] . '</table>', $m_table)) {
            $rows = explode('</tr>', $m_table[1]);
            foreach ($rows as $row) {
                // Robust skip of header or decorative rows for both VAT and Sales Tax table formats
                if (
                    (stripos($row, 'VAT') !== false && stripos($row, 'Price + VAT') !== false) ||
                    (stripos($row, 'Sales tax') !== false && stripos($row, 'Price') !== false && stripos($row, 'LOT') === false)
                ) continue;
                if (empty(trim(strip_tags($row)))) continue;
                
                // BidSpirit Totals table has 5 columns: TH (Label), TD (Price), TD (Empty), TD (VAT), TD (Price+VAT)
                if (preg_match_all('/<t[hd][^>]*>(.*?)<\/t[hd]>/si', $row, $cells)) {
                    $cols = array_map('trim', array_map('strip_tags', $cells[1]));
                    if (count($cols) >= 5) {
                        $data['totals'][] = [
                            'label' => $cols[0],
                            'price' => $cols[1],
                            'vat' => $cols[3],
                            'total' => $cols[4]
                        ];
                    } elseif (count($cols) >= 3) {
                        // Handle simple 3-column fallback for totals
                        $data['totals'][] = [
                            'label' => $cols[0],
                            'price' => $cols[1],
                            'vat' => '',
                            'total' => $cols[2]
                        ];
                    }
                }
            }
        }
        // Also extract items from the main invoice HTML (html_main) which includes
        // all line items: lot items, buyer's premium (with tax rate), shipping, and total tax.
        // This matches the BidSpirit invoice display. The breakdown above only has lot items.
        $main_items = [];
        if (preg_match('/<table[^>]*cellspacing=["\']?0["\']?[^>]*cellpadding=["\']?8["\']?[^>]*>(.*?)<\/table>/si', $html_main, $m_main_table)) {
            $main_rows = explode('</tr>', $m_main_table[1]);
            foreach ($main_rows as $row) {
                // Skip header row
                if (stripos($row, 'LOT') !== false && stripos($row, 'Description') !== false) continue;
                if (empty(trim(strip_tags($row)))) continue;
                
                if (preg_match_all('/<td[^>]*>(.*?)<\/td>/si', $row, $cells)) {
                    if (count($cells[1]) >= 3) {
                        $main_items[] = [
                            'lot' => trim(strip_tags($cells[1][0])),
                            'desc' => trim(strip_tags($cells[1][1])),
                            'price' => trim(strip_tags($cells[1][2])),
                            'premium' => trim(strip_tags($cells[1][3] ?? ''))
                        ];
                    }
                }
            }
        }

        // Prefer main HTML items when they include more rows (buyer's premium, shipping, tax total)
        if (count($main_items) > count($data['items'])) {
            $data['items'] = $main_items;
        }

        // Extract grand total from html_main (bold "Total: $X" line)
        if (preg_match('/font-weight:\s*bold[^>]*>\s*Total:\s*(?:<[^>]+>\s*)*([^\s<]+(?:\s*[\d,]+\.?\d*))/si', $html_main, $m_grand)) {
            $data['grand_total'] = trim(strip_tags($m_grand[1]));
        }

        return $data;
    }

    /**
     * Renders a high-fidelity professional template matching the "JOB ESTIMATE" reference.
     */
    private static function build_professional_template($data) {
        $logo_html = !empty($data['logo']) ? '<img src="'.$data['logo'].'">' : '<h2>'.htmlspecialchars($data['house']['name']).'</h2>';
        
        // Improve status logic: BidSpirit sometimes uses color tags or different phrasing
        $status_text = strtoupper($data['bill']['status']);
        $is_paid = (stripos($status_text, 'PAID') !== false && stripos($status_text, 'NOT PAID') === false);
        
        $status_display = $is_paid ? 'PAID' : 'NOT PAID';
        $status_class = $is_paid ? 'status-paid' : 'status-not-paid';
        
        $items_rows = '';
        foreach ($data['items'] as $item) {
            $items_rows .= '<tr>
                <td style="width: 55px; text-align: center;">' . $item['lot'] . '</td>
                <td>' . $item['desc'] . '</td>
                <td style="width: 90px; text-align: right;">' . $item['price'] . '</td>
                <td style="width: 90px; text-align: right;">' . $item['premium'] . '</td>
            </tr>';
        }

        // Build totals rows
        // When grand_total is available (extracted from main HTML), items table already
        // includes buyer's premium, shipping, and total tax — so just show grand total.
        // Otherwise fall back to the breakdown totals (e.g. for VAT invoices or older formats).
        $totals_rows = '';
        if (!empty($data['grand_total'])) {
            $totals_rows = '<tr style="font-weight: bold; border-top: 2px solid #333; font-size: 14px;">
                <td style="border: none; text-align: right; padding: 4px 10px;">Total</td>
                <td style="border: none; text-align: right; padding: 4px 10px; width: 100px;">' . htmlspecialchars($data['grand_total']) . '</td>
            </tr>';
        } else {
            foreach ($data['totals'] as $total) {
                $label = $total['label'];
                $is_final = (stripos($label, 'Total to pay') !== false);
                $style = $is_final ? 'font-weight: bold; border-top: 2px solid #333; font-size: 14px;' : '';
                
                // Determine the best value to display:
                // - Final row: use 'total' (last column)
                // - Non-final: prefer 'price', fall back to 'vat' or 'total' if price is empty
                if ($is_final) {
                    $display_value = $total['total'];
                } else {
                    $display_value = !empty($total['price']) ? $total['price'] : (!empty($total['vat']) ? $total['vat'] : $total['total']);
                }
                
                $totals_rows .= '<tr style="' . $style . '">
                    <td style="border: none; text-align: right; padding: 4px 10px;">' . $label . '</td>
                    <td style="border: none; text-align: right; padding: 4px 10px; width: 100px;">' . $display_value . '</td>
                </tr>';
            }
        }

        $payment_instructions_html = '';
        if ($status_display !== 'PAID') {
            $payment_instructions_html = '<strong>Payment Instructions:</strong><br>
                Please refer to the online portal for available payment methods. Thank you for your business.';
        } else {
            $payment_instructions_html = '<strong>Thank you!</strong><br>
                This invoice has been successfully paid.';
        }

        return '<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        @page { margin: 0; }
        body { font-family: "Helvetica", "Arial", sans-serif; font-size: 11px; color: #333; margin: 0; padding: 40px; }
        .header-table { width: 100%; border: none; margin-bottom: 30px; }
        .title-block { text-align: right; color: #2e59a8; }
        .title-block h1 { font-size: 28px; margin: 0; text-transform: uppercase; }
        
        .section-bar { background-color: #2e59a8; color: #fff; padding: 6px 12px; font-weight: bold; font-size: 14px; margin-bottom: 10px; text-transform: uppercase; }
        
        .col-container { width: 100%; margin-bottom: 30px; }
        .col { width: 48%; vertical-align: top; }
        .details-box { min-height: 120px; line-height: 1.6; }
        .details-box strong { font-size: 13px; color: #000; }
        
        .auction-bar { background-color: #2e59a8; color: #fff; padding: 8px 15px; font-weight: bold; font-size: 12px; margin-bottom: 15px; }

        table.items-table { width: 100%; border-collapse: collapse; margin-top: 10px; }
        table.items-table th { background-color: #2e59a8; color: #fff; padding: 10px; text-align: left; text-transform: uppercase; font-size: 10px; border: 1px solid #2e59a8; }
        table.items-table td { padding: 10px; border: 1px solid #ddd; vertical-align: top; }
        
        .totals-container { width: 100%; margin-top: 20px; }
        .footer-note { margin-top: 40px; font-size: 9px; color: #777; line-height: 1.5; border-top: 1px solid #eee; padding-top: 10px; }
        
        .status-paid { color: #28a745; font-weight: bold; }
        .status-not-paid { color: #dc3545; font-weight: bold; }
        
        img { max-width: 180px; max-height: 80px; }
    </style>
</head>
<body>
    <table class="header-table">
        <tr>
            <td style="width: 50%;">' . $logo_html . '</td>
            <td class="title-block">
                <h1>INVOICE</h1>
                <div style="margin-top: 10px; color: #555;">
                    Date: ' . $data['bill']['date'] . '<br>
                    Bidder No: ' . $data['bill']['number'] . '<br>
                    Status: <span class="'.$status_class.'">' . $status_display . '</span>
                </div>
            </td>
        </tr>
    </table>

    <table class="col-container">
        <tr>
            <td class="col" style="padding-right: 4%;">
                <div class="section-bar">To</div>
                <div class="details-box">
                    <strong>' . $data['customer']['name'] . '</strong><br>
                    ' . nl2br($data['customer']['address']) . '<br>
                    ' . $data['customer']['phone'] . '<br>
                    ' . $data['customer']['email'] . '
                </div>
            </td>
            <td class="col">
                <div class="section-bar">From</div>
                <div class="details-box">
                    <strong>' . $data['house']['name'] . '</strong><br>
                    ' . nl2br($data['house']['details']) . '
                </div>
            </td>
        </tr>
    </table>

    <div class="auction-bar">AUCTION: ' . strtoupper($data['bill']['auction']) . '</div>

    <table class="items-table">
        <thead>
            <tr>
                <th style="width: 50px; text-align: center;">Lot</th>
                <th>Description</th>
                <th style="text-align: right;">Hammer Price</th>
                <th style="text-align: right;">' . htmlspecialchars($data['tax_label']) . '</th>
            </tr>
        </thead>
        <tbody>
            ' . $items_rows . '
        </tbody>
    </table>

    <table style="width: 100%; margin-top: 20px;">
        <tr>
            <td style="width: 50%; vertical-align: top; font-size: 10px; color: #666; padding-right: 20px;">
                ' . $payment_instructions_html . '
            </td>
            <td style="width: 50%;">
                <table style="width: 100%; border-collapse: collapse;">
                    ' . $totals_rows . '
                </table>
            </td>
        </tr>
    </table>

    <div class="footer-note">
        This document was generated automatically by AuctionForge. Prices are subject to the terms and conditions of ' . $data['house']['name'] . '. Please check the auction catalog for specific ' . htmlspecialchars($data['tax_label']) . ' rules on individual lots.
    </div>
</body>
</html>';
    }

    // Removed obsolete build_pdf_html method


    /**
     * Generate and stream the PDF to the browser.
     */
    private static function generate_pdf($html, $description) {
        // Load Dompdf
        $dompdf_autoload = plugin_dir_path(dirname(dirname(__FILE__)))
            . 'vendor/dompdf/dompdf/autoload.inc.php';

        if (!file_exists($dompdf_autoload)) {
            wp_die('PDF library not installed. Please install dompdf.', 'Error', ['response' => 500]);
        }

        require_once $dompdf_autoload;

        $options = new \Dompdf\Options();
        $options->set('isRemoteEnabled', true);
        $options->set('isHtml5ParserEnabled', true);
        $options->set('defaultFont', 'Helvetica');
        $options->set('tempDir', sys_get_temp_dir());

        $dompdf = new \Dompdf\Dompdf($options);
        $dompdf->loadHtml($html);
        $dompdf->setPaper('A4', 'portrait');
        $dompdf->render();

        // Build a clean filename
        $filename = sanitize_file_name('Invoice_' . preg_replace('/[^a-zA-Z0-9]/', '_', $description)) . '.pdf';

        // Send headers and stream the PDF
        header('Content-Type: application/pdf');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Cache-Control: no-cache, no-store, must-revalidate');

        echo $dompdf->output();
        exit;
    }
}
