<?php
/* Copyright (C) 2026 ZUGFeRD Import Module
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 */

/**
 * \file    class/actions_importzugferd.class.php
 * \ingroup importzugferd
 * \brief   Actions class for ZUGFeRD import operations
 */

require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';

dol_include_once('/importzugferd/class/zugferdparser.class.php');
dol_include_once('/importzugferd/class/zugferdimport.class.php');
dol_include_once('/importzugferd/class/productmapping.class.php');

/**
 * Class ActionsImportZugferd
 * Handles the import process of ZUGFeRD invoices
 */
class ActionsImportZugferd
{
    /**
     * @var DoliDB Database handler
     */
    public $db;

    /**
     * @var string Error message
     */
    public $error = '';

    /**
     * @var array Error messages
     */
    public $errors = array();

    /**
     * @var array Warning messages
     */
    public $warnings = array();

    /**
     * @var ZugferdParser Parser instance
     */
    public $parser;

    /**
     * @var ZugferdImport Import record
     */
    public $import;

    /**
     * @var ProductMapping Mapping helper
     */
    public $mapping;

    /**
     * @var array Import result data
     */
    public $result = array();

    /**
     * @var array Results for hooks
     */
    public $results = array();

    /**
     * Constructor
     *
     * @param DoliDB $db Database handler
     */
    public function __construct($db)
    {
        $this->db = $db;
        $this->parser = new ZugferdParser($db);
        $this->import = new ZugferdImport($db);
        $this->mapping = new ProductMapping($db);
    }

    /**
     * Process a ZUGFeRD PDF file
     *
     * @param string $pdf_path Path to PDF file
     * @param User $user Current user
     * @param bool $create_invoice Whether to create supplier invoice
     * @param bool $force_reimport Whether to bypass duplicate check
     * @return int <0 if KO, >0 if OK (import record ID)
     */
    public function processPdf($pdf_path, $user, $create_invoice = false, $force_reimport = false)
    {
        global $conf;

        $this->result = array(
            'import_id' => 0,
            'invoice_id' => 0,
            'supplier_id' => 0,
            'supplier_found' => false,
            'is_duplicate' => false,
            'lines' => array(),
            'warnings' => array(),
        );

        // Extract XML from PDF
        $res = $this->parser->extractFromPdf($pdf_path);
        if ($res < 0) {
            $this->error = $this->parser->error;
            return -1;
        }

        // Parse XML
        $res = $this->parser->parse();
        if ($res < 0) {
            $this->error = $this->parser->error;
            return -2;
        }

        $invoice_data = $this->parser->getInvoiceData();

        // Check for duplicates
        $file_hash = $this->parser->getFileHash($pdf_path);
        if ($this->import->isDuplicate($file_hash)) {
            if ($force_reimport) {
                // Delete existing import record to allow reimport
                $this->deleteExistingImport($file_hash, $user);
            } else {
                global $langs;
                $langs->load('importzugferd@importzugferd');
                $this->result['is_duplicate'] = true;
                $this->error = $langs->trans('ErrorDuplicateInvoice');
                return -3;
            }
        }

        // Find supplier
        $supplier_id = $this->findSupplier($invoice_data);
        $this->result['supplier_id'] = $supplier_id;
        $this->result['supplier_found'] = ($supplier_id > 0);

        // Create import record
        $this->import->invoice_number = $invoice_data['invoice_number'];
        $this->import->invoice_date = $invoice_data['invoice_date'];
        $this->import->seller_name = $invoice_data['seller']['name'];
        $this->import->seller_vat = $invoice_data['seller']['vat_id'];
        $this->import->buyer_reference = $invoice_data['buyer']['reference'] ?: $invoice_data['buyer']['id'];
        $this->import->total_ht = $invoice_data['totals']['net'];
        $this->import->total_ttc = $invoice_data['totals']['gross'];
        $this->import->currency = $invoice_data['totals']['currency'] ?: 'EUR';
        $this->import->fk_soc = $supplier_id;
        $this->import->xml_content = $this->parser->getXmlContent();
        $this->import->pdf_filename = basename($pdf_path);
        $this->import->file_hash = $file_hash;
        $this->import->status = ZugferdImport::STATUS_IMPORTED;
        $this->import->date_import = dol_now();

        $import_id = $this->import->create($user);
        if ($import_id < 0) {
            $this->error = $this->import->error;
            return -4;
        }

        $this->result['import_id'] = $import_id;

        // Process line items
        $this->result['lines'] = $this->processLineItems($invoice_data['lines'], $supplier_id);

        // Copy PDF to documents folder
        $this->copyToDocuments($pdf_path, $import_id);

        // Create supplier invoice if requested
        if ($create_invoice && $supplier_id > 0) {
            $invoice_id = $this->createSupplierInvoice($invoice_data, $supplier_id, $user, $pdf_path);
            if ($invoice_id > 0) {
                $this->result['invoice_id'] = $invoice_id;
                $this->import->fk_facture_fourn = $invoice_id;

                // Check validation result - status may have been set to ERROR in validateTotals()
                if ($this->import->status != ZugferdImport::STATUS_ERROR) {
                    $this->import->status = ZugferdImport::STATUS_PROCESSED;
                }
                $this->import->update($user);

                // Add validation warning if there was a sum mismatch
                if (!empty($this->result['validation']) && !$this->result['validation']['valid']) {
                    $this->result['warnings'][] = $this->result['validation']['message'];
                }
            } else {
                $this->result['warnings'][] = 'Could not create supplier invoice: ' . $this->error;
            }
        }

        return $import_id;
    }

    /**
     * Find supplier by buyer reference (customer number)
     *
     * @param array $invoice_data Parsed invoice data
     * @return int Supplier ID or 0
     */
    public function findSupplier($invoice_data)
    {
        global $conf;

        $buyer_ref = $invoice_data['buyer']['reference'] ?: $invoice_data['buyer']['id'];
        $seller_vat = $invoice_data['seller']['vat_id'];
        $seller_name = $invoice_data['seller']['name'];

        // 1. Search by buyer reference in extrafield
        if (!empty($buyer_ref)) {
            $sql = "SELECT fk_object FROM " . MAIN_DB_PREFIX . "societe_extrafields";
            $sql .= " WHERE supplier_customer_number = '" . $this->db->escape($buyer_ref) . "'";

            $resql = $this->db->query($sql);
            if ($resql && $this->db->num_rows($resql) > 0) {
                $obj = $this->db->fetch_object($resql);
                return (int) $obj->fk_object;
            }
        }

        // 2. Search by VAT ID
        if (!empty($seller_vat)) {
            $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "societe";
            $sql .= " WHERE tva_intra = '" . $this->db->escape($seller_vat) . "'";
            $sql .= " AND fournisseur = 1";
            $sql .= " AND entity IN (" . getEntity('societe') . ")";

            $resql = $this->db->query($sql);
            if ($resql && $this->db->num_rows($resql) > 0) {
                $obj = $this->db->fetch_object($resql);
                return (int) $obj->rowid;
            }
        }

        // 3. Search by name (fuzzy)
        if (!empty($seller_name)) {
            $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "societe";
            $sql .= " WHERE (nom LIKE '" . $this->db->escape($seller_name) . "%'";
            $sql .= " OR nom LIKE '%" . $this->db->escape(substr($seller_name, 0, 20)) . "%')";
            $sql .= " AND fournisseur = 1";
            $sql .= " AND entity IN (" . getEntity('societe') . ")";
            $sql .= " LIMIT 1";

            $resql = $this->db->query($sql);
            if ($resql && $this->db->num_rows($resql) > 0) {
                $obj = $this->db->fetch_object($resql);
                return (int) $obj->rowid;
            }
        }

        return 0;
    }

    /**
     * Process line items and find matching products
     *
     * @param array $lines Line items from invoice
     * @param int $supplier_id Supplier ID
     * @return array Processed lines with product info
     */
    public function processLineItems($lines, $supplier_id)
    {
        $processed = array();
        $last_product_index = -1;

        foreach ($lines as $idx => $line) {
            // Check if this is a metal surcharge line
            $is_surcharge = $this->isMetalSurchargeLine($line);

            // Get copper surcharge directly from parsed line data (if available)
            $copper_surcharge_per_unit = isset($line['copper_surcharge_per_unit']) ? $line['copper_surcharge_per_unit'] : null;

            $processed_line = array(
                'line_id' => $line['line_id'],
                'supplier_ref' => $line['product']['seller_id'],
                'ean' => $line['product']['global_id'],
                'name' => $line['product']['name'],
                'description' => $line['product']['description'],
                'quantity' => $line['quantity'],
                'unit_code' => $line['unit_code'],
                'unit_price' => $line['unit_price'],
                'unit_price_raw' => isset($line['unit_price_raw']) ? $line['unit_price_raw'] : $line['unit_price'],
                'basis_quantity' => isset($line['basis_quantity']) ? $line['basis_quantity'] : 1,
                'basis_quantity_unit' => isset($line['basis_quantity_unit']) ? $line['basis_quantity_unit'] : '',
                'line_total' => $line['line_total'],
                'tax_percent' => $line['tax_percent'],
                'fk_product' => 0,
                'product_ref' => '',
                'product_label' => '',
                'match_method' => '',
                'needs_creation' => false,
                'is_metal_surcharge' => $is_surcharge,
                'metal_surcharge' => $copper_surcharge_per_unit ?: 0, // From parsed XML or will be filled from surcharge lines
                'copper_surcharge_raw' => isset($line['copper_surcharge']) ? $line['copper_surcharge'] : null,
                'copper_surcharge_basis_qty' => isset($line['copper_surcharge_basis_qty']) ? $line['copper_surcharge_basis_qty'] : null,
            );

            // Try to find product
            if ($supplier_id > 0 && !$is_surcharge) {
                $match = $this->mapping->findProduct($supplier_id, $line['product']);
                if ($match['fk_product'] > 0) {
                    $processed_line['fk_product'] = $match['fk_product'];
                    $processed_line['match_method'] = $match['method'];

                    // Get product info
                    $product = new Product($this->db);
                    if ($product->fetch($match['fk_product']) > 0) {
                        $processed_line['product_ref'] = $product->ref;
                        $processed_line['product_label'] = $product->label;
                    }

                    // Update supplier price with EAN from invoice if empty
                    $invoiceEan = !empty($line['product']['global_id']) ? trim($line['product']['global_id']) : '';
                    $supplierRef = !empty($line['product']['seller_id']) ? $line['product']['seller_id'] : '';
                    if (!empty($invoiceEan) && !empty($supplierRef) && ctype_digit($invoiceEan)) {
                        // Barcode-Typ basierend auf Länge bestimmen
                        $eanLen = strlen($invoiceEan);
                        if ($eanLen == 13) {
                            $barcodeType = 2; // EAN13
                        } elseif ($eanLen == 8) {
                            $barcodeType = 1; // EAN8
                        } elseif ($eanLen == 12) {
                            $barcodeType = 3; // UPC-A
                        } else {
                            $barcodeType = 0; // Unbekannt
                        }

                        $sqlEan = "UPDATE " . MAIN_DB_PREFIX . "product_fournisseur_price";
                        $sqlEan .= " SET barcode = '" . $this->db->escape($invoiceEan) . "'";
                        $sqlEan .= ", fk_barcode_type = " . (int)$barcodeType;
                        $sqlEan .= " WHERE fk_product = " . (int)$match['fk_product'];
                        $sqlEan .= " AND fk_soc = " . (int)$supplier_id;
                        $sqlEan .= " AND ref_fourn = '" . $this->db->escape($supplierRef) . "'";
                        $sqlEan .= " AND (barcode IS NULL OR barcode = '')";
                        $this->db->query($sqlEan);
                    }
                } else {
                    $processed_line['needs_creation'] = true;
                }
            } elseif (!$is_surcharge) {
                $processed_line['needs_creation'] = true;
            }

            $processed[] = $processed_line;
            $current_index = count($processed) - 1;

            // If this is a metal surcharge line, associate it with the previous product
            // Only use this fallback if the product line doesn't already have copper_surcharge from XML
            if ($is_surcharge && $last_product_index >= 0) {
                // Only apply if the previous product doesn't already have a copper surcharge from XML
                if (empty($processed[$last_product_index]['metal_surcharge'])) {
                    // Calculate surcharge per unit based on the product's quantity
                    $product_qty = $processed[$last_product_index]['quantity'];
                    if ($product_qty > 0) {
                        $surcharge_per_unit = $line['line_total'] / $product_qty;
                        $processed[$last_product_index]['metal_surcharge'] = $surcharge_per_unit;

                        dol_syslog("Metal surcharge from separate line: " . $line['line_total'] . " EUR for " . $product_qty . " units = " . $surcharge_per_unit . " EUR/unit", LOG_INFO);
                    }
                }

                // Copy product info to surcharge line for reference
                $processed_line['fk_product'] = $processed[$last_product_index]['fk_product'];
                $processed_line['associated_product_ref'] = $processed[$last_product_index]['product_ref'];
                $processed[$current_index] = $processed_line;
            }

            // Log if copper surcharge was extracted from XML
            if ($copper_surcharge_per_unit > 0) {
                dol_syslog("Copper surcharge from XML: " . $copper_surcharge_per_unit . " EUR/unit for " . $line['product']['name'], LOG_INFO);
            }

            // Remember the last non-surcharge product line
            if (!$is_surcharge && $processed_line['fk_product'] > 0) {
                $last_product_index = $current_index;
            }
        }

        return $processed;
    }

    /**
     * Create supplier invoice from parsed data
     *
     * @param array $invoice_data Parsed invoice data
     * @param int $supplier_id Supplier ID
     * @param User $user Current user
     * @param string $pdf_path Path to source PDF file (optional)
     * @return int Invoice ID or <0 if error
     */
    public function createSupplierInvoice($invoice_data, $supplier_id, $user, $pdf_path = '')
    {
        global $conf, $langs;

        $invoice = new FactureFournisseur($this->db);

        $invoice->socid = $supplier_id;
        $invoice->ref_supplier = $invoice_data['invoice_number'];
        $invoice->date = strtotime($invoice_data['invoice_date']);
        $invoice->date_echeance = !empty($invoice_data['due_date']) ? strtotime($invoice_data['due_date']) : null;
        $invoice->note_private = $langs->trans('ImportedFromZugferd') . ' - ' . $this->import->ref;
        $invoice->multicurrency_code = $invoice_data['totals']['currency'] ?: 'EUR';

        // Set invoice label to the most expensive item's name
        $invoice->libelle = $this->getMostExpensiveItemName($this->result['lines']);

        $this->db->begin();

        $invoice_id = $invoice->create($user);
        if ($invoice_id < 0) {
            $this->error = $invoice->error;
            $this->db->rollback();
            return -1;
        }

        // Add lines
        foreach ($this->result['lines'] as $line) {
            $result = $this->addInvoiceLine($invoice, $line, $user);
            if ($result < 0) {
                $this->db->rollback();
                return -2;
            }
        }

        $this->db->commit();

        // Validate totals - re-fetch invoice to get calculated totals
        $invoice->fetch($invoice_id);
        $validation_result = $this->validateTotals($invoice_data, $invoice);
        $this->result['validation'] = $validation_result;

        // Attach PDF to supplier invoice
        if (!empty($pdf_path) && file_exists($pdf_path)) {
            $this->attachPdfToInvoice($invoice, $pdf_path);
        }

        return $invoice_id;
    }

    /**
     * Attach PDF file to supplier invoice
     *
     * @param FactureFournisseur $invoice Invoice object
     * @param string $pdf_path Source PDF path
     * @return bool Success
     */
    public function attachPdfToInvoice($invoice, $pdf_path)
    {
        global $conf;

        // Get supplier for folder name
        $supplier = new Societe($this->db);
        $supplier->fetch($invoice->socid);

        // Build destination directory path for supplier invoice
        // Format: DOL_DATA_ROOT/fournisseur/facture/[thirdparty_name]/[invoice_ref]/
        $destdir = $conf->fournisseur->facture->dir_output;
        $destdir .= '/' . dol_sanitizeFileName($supplier->nom);
        $destdir .= '/' . dol_sanitizeFileName($invoice->ref);

        // Create directory if it doesn't exist
        if (!is_dir($destdir)) {
            dol_mkdir($destdir);
        }

        // Build descriptive filename
        // Format: YYYY-MM-DD - Lieferant - Rechnungsnummer - Material - Preis EUR.pdf
        $newFilename = $this->buildInvoiceFilename($invoice, $supplier);
        $destfile = $destdir . '/' . $newFilename;

        if (copy($pdf_path, $destfile)) {
            dol_syslog("Attached PDF as " . $newFilename . " to supplier invoice " . $invoice->ref, LOG_INFO);
            return true;
        }

        return false;
    }

    /**
     * Build descriptive filename for invoice PDF
     * Format: YYYY-MM-DD - Lieferant - Rechnungsnummer - Material - Preis EUR.pdf
     *
     * @param FactureFournisseur $invoice Invoice object
     * @param Societe $supplier Supplier object
     * @return string Filename
     */
    private function buildInvoiceFilename($invoice, $supplier)
    {
        // Date: YYYY-MM-DD
        $date = dol_print_date($invoice->date, '%Y-%m-%d');

        // Supplier name (shortened if too long)
        $supplierName = dol_sanitizeFileName($supplier->nom);
        if (strlen($supplierName) > 30) {
            $supplierName = substr($supplierName, 0, 30);
        }

        // Invoice number from supplier
        $invoiceNumber = dol_sanitizeFileName($invoice->ref_supplier);
        if (empty($invoiceNumber)) {
            $invoiceNumber = $invoice->ref;
        }

        // Get material description from first line item or use generic term
        $material = 'Material';
        if (!empty($this->result['lines'])) {
            // Try to get a meaningful description from line items
            $firstLine = reset($this->result['lines']);
            if (!empty($firstLine['name'])) {
                // Use first product name, shortened
                $material = dol_sanitizeFileName($firstLine['name']);
                if (strlen($material) > 25) {
                    $material = substr($material, 0, 25);
                }
            }
            // If multiple lines, indicate it
            if (count($this->result['lines']) > 1) {
                $material .= ' ua';  // "und andere" / "and others"
            }
        }

        // Price rounded
        $price = round($invoice->total_ttc);

        // Build filename
        $filename = sprintf(
            '%s - %s - %s - %s - %d EUR.pdf',
            $date,
            $supplierName,
            $invoiceNumber,
            $material,
            $price
        );

        // Clean up any double spaces or invalid characters
        $filename = preg_replace('/\s+/', ' ', $filename);
        $filename = str_replace(['/', '\\', ':', '*', '?', '"', '<', '>', '|'], '-', $filename);

        return $filename;
    }

    /**
     * Validate that ZUGFeRD totals match Dolibarr calculated totals
     *
     * @param array $invoice_data Parsed ZUGFeRD invoice data
     * @param FactureFournisseur $invoice Created Dolibarr invoice
     * @return array Validation result with status and message
     */
    public function validateTotals($invoice_data, $invoice)
    {
        global $langs;
        $langs->load('importzugferd@importzugferd');

        $result = array(
            'valid' => true,
            'zugferd_ht' => (float) $invoice_data['totals']['net'],
            'zugferd_ttc' => (float) $invoice_data['totals']['gross'],
            'dolibarr_ht' => (float) $invoice->total_ht,
            'dolibarr_ttc' => (float) $invoice->total_ttc,
            'diff_ht' => 0,
            'diff_ttc' => 0,
            'message' => '',
        );

        $result['diff_ht'] = abs($result['zugferd_ht'] - $result['dolibarr_ht']);
        $result['diff_ttc'] = abs($result['zugferd_ttc'] - $result['dolibarr_ttc']);

        // Allow small deviations (max 0.05€ per total)
        $tolerance = 0.05;

        if ($result['diff_ht'] > $tolerance || $result['diff_ttc'] > $tolerance) {
            $result['valid'] = false;
            $result['message'] = $langs->trans(
                'SumValidationError',
                price($result['zugferd_ttc']),
                price($result['dolibarr_ttc']),
                price($result['diff_ttc'])
            );

            // Update import record with error
            $this->import->status = ZugferdImport::STATUS_ERROR;
            $this->import->error_message = $result['message'];
        } else {
            $result['message'] = $langs->trans('SumValidationOk');
            // Keep status as PROCESSED (already set)
        }

        return $result;
    }

    /**
     * Add a line to supplier invoice
     *
     * @param FactureFournisseur $invoice Invoice object
     * @param array $line Line data
     * @param User $user Current user
     * @return int >0 if OK, <0 if error
     */
    private function addInvoiceLine($invoice, $line, $user)
    {
        $desc = $line['name'];
        if (!empty($line['description']) && $line['description'] != $line['name']) {
            $desc .= "\n" . $line['description'];
        }

        // Add supplier reference to description if no product found
        if ($line['fk_product'] == 0 && !empty($line['supplier_ref'])) {
            $desc .= "\n[" . $line['supplier_ref'] . "]";
        }

        // Determine VAT rate
        $tva_tx = $line['tax_percent'] ?: 19;

        // Add line
        $result = $invoice->addline(
            $desc,                          // description
            $line['unit_price'],            // pu_ht
            $tva_tx,                        // tva_tx
            0,                              // localtax1_tx
            0,                              // localtax2_tx
            $line['quantity'],              // qty
            $line['fk_product'] ?: 0,       // fk_product
            0,                              // remise_percent
            '',                             // date_start
            '',                             // date_end
            0,                              // ventil
            0,                              // info_bits
            'HT',                           // price_base_type
            0,                              // type (0=product, 1=service)
            -1,                             // rang
            0,                              // notrigger
            array(),                        // array_options
            '',                             // fk_unit
            0,                              // origin_id
            0,                              // pu_ht_devise
            $line['supplier_ref'] ?: ''     // ref_supplier
        );

        if ($result < 0) {
            $this->error = $invoice->error;
            return -1;
        }

        // Update supplier price with EAN if product was matched and EAN is available
        if ($line['fk_product'] > 0 && !empty($line['ean'])) {
            $this->updateSupplierPriceBarcode($invoice->socid, $line['fk_product'], $line['ean'], $line['supplier_ref']);
        }

        // Check if this line has a metal surcharge associated and update extrafield
        if ($line['fk_product'] > 0 && !empty($line['metal_surcharge']) && $line['metal_surcharge'] > 0) {
            $this->updateSupplierPriceMetalSurcharge(
                $invoice->socid,
                $line['fk_product'],
                $line['metal_surcharge'],
                $line['supplier_ref']
            );
        }

        return 1;
    }

    /**
     * Check if a line is a metal surcharge line
     *
     * @param array $line Line data from invoice
     * @return bool
     */
    public function isMetalSurchargeLine($line)
    {
        $name = strtolower($line['product']['name'] ?? '');
        $description = strtolower($line['product']['description'] ?? '');
        $text = $name . ' ' . $description;

        // Keywords that indicate metal surcharge
        $keywords = array(
            'metallzuschlag',
            'kupferzuschlag',
            'cu-zuschlag',
            'cuzuschlag',
            'metallnotierung',
            'kupfernotierung',
            'metal surcharge',
            'copper surcharge',
            'metallaufschlag',
            'kupferaufschlag',
            'mez ', // MEZ = Metallzuschlag (with space to avoid false positives)
            ' mez',
        );

        foreach ($keywords as $keyword) {
            if (strpos($text, $keyword) !== false) {
                return true;
            }
        }

        return false;
    }

    /**
     * Update metal surcharge extrafield on supplier price
     *
     * @param int $supplier_id Supplier ID
     * @param int $product_id Product ID
     * @param float $surcharge Metal surcharge amount per unit
     * @param string $ref_fourn Supplier reference
     * @return int >0 if updated, 0 if no update, <0 if error
     */
    public function updateSupplierPriceMetalSurcharge($supplier_id, $product_id, $surcharge, $ref_fourn = '')
    {
        global $conf;

        if ($surcharge <= 0) {
            return 0;
        }

        // Find supplier price record
        $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "product_fournisseur_price";
        $sql .= " WHERE fk_soc = " . (int) $supplier_id;
        $sql .= " AND fk_product = " . (int) $product_id;
        $sql .= " AND entity IN (" . getEntity('product') . ")";
        if (!empty($ref_fourn)) {
            $sql .= " AND ref_fourn = '" . $this->db->escape($ref_fourn) . "'";
        }
        $sql .= " ORDER BY rowid DESC LIMIT 1";

        $resql = $this->db->query($sql);
        if ($resql && $this->db->num_rows($resql) > 0) {
            $obj = $this->db->fetch_object($resql);
            $price_id = $obj->rowid;

            // Check if extrafield table exists
            $sql_check = "SHOW TABLES LIKE '" . MAIN_DB_PREFIX . "product_fournisseur_price_extrafields'";
            $res_check = $this->db->query($sql_check);
            if (!$res_check || $this->db->num_rows($res_check) == 0) {
                dol_syslog("Extrafield table does not exist, skipping metal surcharge update", LOG_WARNING);
                return 0;
            }

            // Check if record exists in extrafields
            $sql_exists = "SELECT rowid FROM " . MAIN_DB_PREFIX . "product_fournisseur_price_extrafields";
            $sql_exists .= " WHERE fk_object = " . (int) $price_id;

            $res_exists = $this->db->query($sql_exists);
            if ($res_exists && $this->db->num_rows($res_exists) > 0) {
                // Update existing record
                $sql_update = "UPDATE " . MAIN_DB_PREFIX . "product_fournisseur_price_extrafields";
                $sql_update .= " SET kupferzuschlag = " . (float) $surcharge;
                $sql_update .= " WHERE fk_object = " . (int) $price_id;
            } else {
                // Insert new record
                $sql_update = "INSERT INTO " . MAIN_DB_PREFIX . "product_fournisseur_price_extrafields";
                $sql_update .= " (fk_object, kupferzuschlag) VALUES (" . (int) $price_id . ", " . (float) $surcharge . ")";
            }

            $res = $this->db->query($sql_update);
            if ($res) {
                dol_syslog("Updated metal surcharge for product " . $product_id . " supplier " . $supplier_id . " to " . $surcharge, LOG_INFO);
                return 1;
            } else {
                dol_syslog("Error updating metal surcharge: " . $this->db->lasterror(), LOG_ERR);
                return -1;
            }
        }

        return 0; // No supplier price record found
    }

    /**
     * Update barcode in supplier price record
     *
     * @param int $supplier_id Supplier ID
     * @param int $product_id Product ID
     * @param string $barcode EAN/GTIN barcode
     * @param string $ref_fourn Supplier reference (optional, to identify correct price record)
     * @return int >0 if updated, 0 if no update needed, <0 if error
     */
    public function updateSupplierPriceBarcode($supplier_id, $product_id, $barcode, $ref_fourn = '')
    {
        global $conf;

        // Check if barcode column exists in product_fournisseur_price table
        if (!$this->checkSupplierPriceBarcodeColumn()) {
            return 0; // Column doesn't exist, skip update
        }

        // Find supplier price record
        $sql = "SELECT rowid, barcode FROM " . MAIN_DB_PREFIX . "product_fournisseur_price";
        $sql .= " WHERE fk_soc = " . (int) $supplier_id;
        $sql .= " AND fk_product = " . (int) $product_id;
        $sql .= " AND entity IN (" . getEntity('product') . ")";
        if (!empty($ref_fourn)) {
            $sql .= " AND ref_fourn = '" . $this->db->escape($ref_fourn) . "'";
        }
        $sql .= " ORDER BY rowid DESC LIMIT 1";

        $resql = $this->db->query($sql);
        if ($resql && $this->db->num_rows($resql) > 0) {
            $obj = $this->db->fetch_object($resql);

            // Only update if barcode is empty or different
            if (empty($obj->barcode) || $obj->barcode != $barcode) {
                $sql_update = "UPDATE " . MAIN_DB_PREFIX . "product_fournisseur_price";
                $sql_update .= " SET barcode = '" . $this->db->escape($barcode) . "'";
                $sql_update .= " WHERE rowid = " . (int) $obj->rowid;

                $res = $this->db->query($sql_update);
                if ($res) {
                    dol_syslog("Updated supplier price barcode for product " . $product_id . " supplier " . $supplier_id . " to " . $barcode, LOG_DEBUG);
                    return 1;
                } else {
                    return -1;
                }
            }
            return 0; // No update needed
        }

        return 0; // No supplier price record found
    }

    /**
     * Check if barcode column exists in product_fournisseur_price table
     *
     * @return bool
     */
    private function checkSupplierPriceBarcodeColumn()
    {
        static $has_barcode_column = null;

        if ($has_barcode_column === null) {
            $sql = "SHOW COLUMNS FROM " . MAIN_DB_PREFIX . "product_fournisseur_price LIKE 'barcode'";
            $resql = $this->db->query($sql);
            $has_barcode_column = ($resql && $this->db->num_rows($resql) > 0);
        }

        return $has_barcode_column;
    }

    /**
     * Delete existing import record by file hash (for reimport)
     *
     * @param string $file_hash File hash
     * @param User $user Current user
     * @return int >0 if deleted, 0 if not found, <0 if error
     */
    public function deleteExistingImport($file_hash, $user)
    {
        global $conf;

        // Find existing import by hash
        $existingImport = new ZugferdImport($this->db);
        $result = $existingImport->fetch(0, null, $file_hash);

        if ($result > 0) {
            // Delete the existing import record
            $deleteResult = $existingImport->delete($user);
            if ($deleteResult > 0) {
                dol_syslog("Deleted existing import record " . $existingImport->ref . " for reimport", LOG_INFO);
                return 1;
            } else {
                $this->error = $existingImport->error;
                return -1;
            }
        }

        return 0; // Not found
    }

    /**
     * Copy PDF to documents folder
     *
     * @param string $pdf_path Source PDF path
     * @param int $import_id Import record ID
     * @return bool
     */
    public function copyToDocuments($pdf_path, $import_id)
    {
        global $conf;

        $destdir = $conf->importzugferd->dir_output . '/imports';
        if (!is_dir($destdir)) {
            dol_mkdir($destdir);
        }

        $destfile = $destdir . '/' . $this->import->ref . '_' . basename($pdf_path);

        return copy($pdf_path, $destfile);
    }

    /**
     * Get the name of the most expensive item from invoice lines
     *
     * @param array $lines Processed invoice lines
     * @return string Name of the most expensive item
     */
    public function getMostExpensiveItemName($lines)
    {
        $maxTotal = 0;
        $itemName = '';

        foreach ($lines as $line) {
            // Skip metal surcharge lines
            if (!empty($line['is_metal_surcharge'])) {
                continue;
            }

            $lineTotal = (float) $line['line_total'];
            if ($lineTotal > $maxTotal) {
                $maxTotal = $lineTotal;
                // Use product label if available, otherwise use name from invoice
                $itemName = !empty($line['product_label']) ? $line['product_label'] : $line['name'];
            }
        }

        return $itemName;
    }

    /**
     * Get import result
     *
     * @return array
     */
    public function getResult()
    {
        return $this->result;
    }

    /**
     * Get parsed invoice data
     *
     * @return array
     */
    public function getInvoiceData()
    {
        return $this->parser->getInvoiceData();
    }

    /**
     * Hook to add dashboard line for new products
     *
     * @param array $parameters Parameters
     * @param object $object Object
     * @param string $action Action
     * @param HookManager $hookmanager Hook manager
     * @return int 0 = OK, >0 = number of errors
     */
    public function addOpenElementsDashboardLine($parameters, &$object, &$action, $hookmanager)
    {
        global $langs, $user;

        if (!$user->hasRight('produit', 'lire')) {
            return 0;
        }

        require_once DOL_DOCUMENT_ROOT.'/core/class/workboardresponse.class.php';
        $langs->load('importzugferd@importzugferd');

        $sql = "SELECT COUNT(*) as total FROM " . MAIN_DB_PREFIX . "product";
        $sql .= " WHERE entity IN (" . getEntity('product') . ")";
        $sql .= " AND ref LIKE 'New%'";

        $resql = $this->db->query($sql);
        if ($resql) {
            $obj = $this->db->fetch_object($resql);
            $count = (int) $obj->total;

            if ($count > 0) {
                $response = new WorkboardResponse();
                $response->warning_delay = 0;
                $response->label = $langs->trans("NewProductsToReview");
                $response->labelShort = $langs->trans("NewProductsToReview");
                $response->url = dol_buildpath('/importzugferd/new_products.php', 1);
                $response->img = 'product';
                $response->nbtodo = $count;
                $response->nbtodolate = 0;

                $this->results['importzugferd_newproducts'] = $response;
            }
        }

        return 0;
    }

    /**
     * Hook to add dashboard group for new products
     *
     * @param array $parameters Parameters
     * @param object $object Object
     * @param string $action Action
     * @param HookManager $hookmanager Hook manager
     * @return int 0 = OK, >0 = number of errors
     */
    public function addOpenElementsDashboardGroup($parameters, &$object, &$action, $hookmanager)
    {
        global $langs;

        $langs->load('importzugferd@importzugferd');

        $this->results['importzugferd_newproducts'] = array(
            'groupName' => $langs->trans("NewProductsToReview"),
            'stats' => array('importzugferd_newproducts'),
        );

        return 0;
    }

    /**
     * Hook to add info box on products/services dashboard page
     *
     * @param array $parameters Parameters
     * @param object $object Object
     * @param string $action Action
     * @param HookManager $hookmanager Hook manager
     * @return int 0 = OK, >0 = number of errors
     */
    public function dashboardProductsServices($parameters, &$object, &$action, $hookmanager)
    {
        global $langs, $user, $conf;

        if (!$user->hasRight('produit', 'lire')) {
            return 0;
        }

        $langs->load('importzugferd@importzugferd');

        // Count products with ref starting with "New"
        $sql = "SELECT COUNT(*) as total FROM " . MAIN_DB_PREFIX . "product";
        $sql .= " WHERE entity IN (" . getEntity('product') . ")";
        $sql .= " AND ref LIKE 'New%'";

        $resql = $this->db->query($sql);
        if ($resql) {
            $obj = $this->db->fetch_object($resql);
            $count = (int) $obj->total;

            if ($count > 0) {
                $url = dol_buildpath('/importzugferd/new_products.php', 1);

                $this->resprints = '
                <div class="box-flex-item">
                    <div class="box-flex-item-with-margin">
                        <div class="info-box info-box-sm">
                            <span class="info-box-icon bg-infobox-importzugferd_newproducts">
                                <i class="fa fa-dol-importzugferd_newproducts"></i>
                            </span>
                            <div class="info-box-content">
                                <span class="info-box-text">' . $langs->trans("NewProductsToReview") . '</span>
                                <span class="info-box-number">
                                    <a href="' . $url . '">' . $count . ' ' . $langs->trans("Products") . '</a>
                                </span>
                            </div>
                        </div>
                    </div>
                </div>';
            }
        }

        return 0;
    }
}
