<?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/zugferdimport.class.php
 * \ingroup importzugferd
 * \brief   Class for ZUGFeRD import records
 */

require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';

/**
 * Class ZugferdImport
 * Manages imported ZUGFeRD invoices
 */
class ZugferdImport extends CommonObject
{
    /**
     * @var string ID to identify managed object
     */
    public $element = 'zugferdimport';

    /**
     * @var string Name of table without prefix
     */
    public $table_element = 'importzugferd_import';

    /**
     * @var int Does object support multicompany
     */
    public $ismultientitymanaged = 1;

    /**
     * @var string Field with ID of parent key if object has a parent
     */
    public $fk_element = 'fk_zugferdimport';

    /**
     * @var array Fields definition
     */
    public $fields = array(
        'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'visible' => 0, 'index' => 1),
        'ref' => array('type' => 'varchar(128)', 'label' => 'Ref', 'enabled' => 1, 'position' => 10, 'notnull' => 1, 'visible' => 4, 'index' => 1, 'searchall' => 1),
        'invoice_number' => array('type' => 'varchar(128)', 'label' => 'InvoiceNumber', 'enabled' => 1, 'position' => 20, 'notnull' => 1, 'visible' => 1, 'searchall' => 1),
        'invoice_date' => array('type' => 'date', 'label' => 'InvoiceDate', 'enabled' => 1, 'position' => 30, 'notnull' => 1, 'visible' => 1),
        'seller_name' => array('type' => 'varchar(255)', 'label' => 'SellerName', 'enabled' => 1, 'position' => 40, 'notnull' => 0, 'visible' => 1, 'searchall' => 1),
        'seller_vat' => array('type' => 'varchar(50)', 'label' => 'SellerVAT', 'enabled' => 1, 'position' => 50, 'notnull' => 0, 'visible' => 1),
        'buyer_reference' => array('type' => 'varchar(128)', 'label' => 'BuyerReference', 'enabled' => 1, 'position' => 60, 'notnull' => 0, 'visible' => 1),
        'total_ht' => array('type' => 'price', 'label' => 'TotalHT', 'enabled' => 1, 'position' => 70, 'notnull' => 0, 'visible' => 1),
        'total_ttc' => array('type' => 'price', 'label' => 'TotalTTC', 'enabled' => 1, 'position' => 80, 'notnull' => 0, 'visible' => 1),
        'currency' => array('type' => 'varchar(3)', 'label' => 'Currency', 'enabled' => 1, 'position' => 90, 'notnull' => 0, 'visible' => 1, 'default' => 'EUR'),
        'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'Supplier', 'enabled' => 1, 'position' => 100, 'notnull' => 0, 'visible' => 1),
        'fk_facture_fourn' => array('type' => 'integer:FactureFournisseur:fourn/class/fournisseur.facture.class.php', 'label' => 'SupplierInvoice', 'enabled' => 1, 'position' => 110, 'notnull' => 0, 'visible' => 1),
        'status' => array('type' => 'integer', 'label' => 'Status', 'enabled' => 1, 'position' => 500, 'notnull' => 1, 'visible' => 2, 'default' => 0, 'index' => 1, 'arrayofkeyval' => array(0 => 'Imported', 1 => 'Processed', 2 => 'Error')),
        'error_message' => array('type' => 'text', 'label' => 'ErrorMessage', 'enabled' => 1, 'position' => 510, 'notnull' => 0, 'visible' => 0),
        'file_hash' => array('type' => 'varchar(64)', 'label' => 'FileHash', 'enabled' => 1, 'position' => 520, 'notnull' => 0, 'visible' => 0),
        'pdf_filename' => array('type' => 'varchar(255)', 'label' => 'PDFFilename', 'enabled' => 1, 'position' => 530, 'notnull' => 0, 'visible' => 1),
        'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 600, 'notnull' => 1, 'visible' => 2),
        'date_import' => array('type' => 'datetime', 'label' => 'DateImport', 'enabled' => 1, 'position' => 610, 'notnull' => 0, 'visible' => 2),
        'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'position' => 620, 'notnull' => 0, 'visible' => 0),
        'fk_user_creat' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserCreator', 'enabled' => 1, 'position' => 700, 'notnull' => 0, 'visible' => 0),
        'fk_user_modif' => array('type' => 'integer:User:User/class/user.class.php', 'label' => 'UserModifier', 'enabled' => 1, 'position' => 710, 'notnull' => 0, 'visible' => 0),
        'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportKey', 'enabled' => 1, 'position' => 800, 'notnull' => 0, 'visible' => 0),
        'entity' => array('type' => 'integer', 'label' => 'Entity', 'enabled' => 1, 'position' => 900, 'notnull' => 1, 'visible' => 0, 'default' => 1, 'index' => 1),
    );

    /**
     * @var string Ref
     */
    public $ref;

    /**
     * @var string Invoice number from ZUGFeRD
     */
    public $invoice_number;

    /**
     * @var string Invoice date
     */
    public $invoice_date;

    /**
     * @var string Seller name
     */
    public $seller_name;

    /**
     * @var string Seller VAT ID
     */
    public $seller_vat;

    /**
     * @var string Buyer reference (our customer number at supplier)
     */
    public $buyer_reference;

    /**
     * @var float Net total
     */
    public $total_ht;

    /**
     * @var float Gross total
     */
    public $total_ttc;

    /**
     * @var string Currency
     */
    public $currency = 'EUR';

    /**
     * @var int Supplier ID
     */
    public $fk_soc;

    /**
     * @var int Created supplier invoice ID
     */
    public $fk_facture_fourn;

    /**
     * @var string XML content
     */
    public $xml_content;

    /**
     * @var string PDF filename
     */
    public $pdf_filename;

    /**
     * @var string File hash for duplicate detection
     */
    public $file_hash;

    /**
     * @var int Status: 0=imported, 1=processed, 2=error
     */
    public $status = 0;

    /**
     * @var string Error message
     */
    public $error_message;

    /**
     * @var string Date creation
     */
    public $date_creation;

    /**
     * @var string Date import
     */
    public $date_import;

    /**
     * @var int User creator
     */
    public $fk_user_creat;

    /**
     * @var int User modifier
     */
    public $fk_user_modif;

    /**
     * @var string Import key
     */
    public $import_key;

    /**
     * @var array Parsed line items
     */
    public $lines = array();

    /**
     * Status constants
     */
    const STATUS_IMPORTED = 0;
    const STATUS_PROCESSED = 1;
    const STATUS_ERROR = 2;
    const STATUS_PENDING = 3;  // Pending manual product assignment

    /**
     * Constructor
     *
     * @param DoliDB $db Database handler
     */
    public function __construct($db)
    {
        global $conf, $langs;

        $this->db = $db;

        if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
            $this->fields['rowid']['visible'] = 0;
        }
    }

    /**
     * Create object into database
     *
     * @param User $user User that creates
     * @param bool $notrigger false=launch triggers, true=disable triggers
     * @return int <0 if KO, Id of created object if OK
     */
    public function create($user, $notrigger = false)
    {
        global $conf;

        $this->entity = $conf->entity;

        if (empty($this->ref)) {
            $this->ref = $this->getNextRef();
        }

        if (empty($this->date_creation)) {
            $this->date_creation = dol_now();
        }

        $this->fk_user_creat = $user->id;

        $sql = "INSERT INTO " . MAIN_DB_PREFIX . $this->table_element . " (";
        $sql .= "ref, invoice_number, invoice_date, seller_name, seller_vat, buyer_reference,";
        $sql .= "total_ht, total_ttc, currency, fk_soc, fk_facture_fourn,";
        $sql .= "xml_content, pdf_filename, file_hash, status, error_message,";
        $sql .= "date_creation, date_import, fk_user_creat, import_key, entity";
        $sql .= ") VALUES (";
        $sql .= "'" . $this->db->escape($this->ref) . "',";
        $sql .= "'" . $this->db->escape($this->invoice_number) . "',";
        $sql .= "'" . $this->db->escape($this->invoice_date) . "',";
        $sql .= "'" . $this->db->escape($this->seller_name) . "',";
        $sql .= "'" . $this->db->escape($this->seller_vat) . "',";
        $sql .= "'" . $this->db->escape($this->buyer_reference) . "',";
        $sql .= price2num($this->total_ht) . ",";
        $sql .= price2num($this->total_ttc) . ",";
        $sql .= "'" . $this->db->escape($this->currency) . "',";
        $sql .= ($this->fk_soc > 0 ? $this->fk_soc : "null") . ",";
        $sql .= ($this->fk_facture_fourn > 0 ? $this->fk_facture_fourn : "null") . ",";
        // Normalize XML before storing (compact format without whitespace)
        $normalizedXml = self::normalizeXml($this->xml_content);
        $sql .= "'" . $this->db->escape($normalizedXml) . "',";
        $sql .= "'" . $this->db->escape($this->pdf_filename) . "',";
        $sql .= "'" . $this->db->escape($this->file_hash) . "',";
        $sql .= (int) $this->status . ",";
        $sql .= "'" . $this->db->escape($this->error_message) . "',";
        $sql .= "'" . $this->db->escape($this->db->idate($this->date_creation)) . "',";
        $sql .= ($this->date_import ? "'" . $this->db->escape($this->db->idate($this->date_import)) . "'" : "null") . ",";
        $sql .= (int) $this->fk_user_creat . ",";
        $sql .= "'" . $this->db->escape($this->import_key) . "',";
        $sql .= (int) $this->entity;
        $sql .= ")";

        $this->db->begin();

        dol_syslog(get_class($this) . "::create", LOG_DEBUG);
        $resql = $this->db->query($sql);

        if (!$resql) {
            $this->error = $this->db->lasterror();
            $this->db->rollback();
            return -1;
        }

        $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);

        $this->db->commit();
        return $this->id;
    }

    /**
     * Load object in memory from database
     *
     * @param int $id Id object
     * @param string $ref Ref
     * @param string $file_hash File hash
     * @return int <0 if KO, 0 if not found, >0 if OK
     */
    public function fetch($id, $ref = null, $file_hash = null)
    {
        global $conf;

        $sql = "SELECT rowid, ref, invoice_number, invoice_date, seller_name, seller_vat, buyer_reference,";
        $sql .= " total_ht, total_ttc, currency, fk_soc, fk_facture_fourn,";
        $sql .= " xml_content, pdf_filename, file_hash, status, error_message,";
        $sql .= " date_creation, date_import, tms, fk_user_creat, fk_user_modif, import_key, entity";
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
        $sql .= " WHERE entity IN (" . getEntity($this->table_element) . ")";

        if ($id) {
            $sql .= " AND rowid = " . (int) $id;
        } elseif ($ref) {
            $sql .= " AND ref = '" . $this->db->escape($ref) . "'";
        } elseif ($file_hash) {
            $sql .= " AND file_hash = '" . $this->db->escape($file_hash) . "'";
        } else {
            return -1;
        }

        dol_syslog(get_class($this) . "::fetch", LOG_DEBUG);
        $resql = $this->db->query($sql);

        if ($resql) {
            if ($this->db->num_rows($resql)) {
                $obj = $this->db->fetch_object($resql);

                $this->id = $obj->rowid;
                $this->ref = $obj->ref;
                $this->invoice_number = $obj->invoice_number;
                $this->invoice_date = $this->db->jdate($obj->invoice_date);
                $this->seller_name = $obj->seller_name;
                $this->seller_vat = $obj->seller_vat;
                $this->buyer_reference = $obj->buyer_reference;
                $this->total_ht = $obj->total_ht;
                $this->total_ttc = $obj->total_ttc;
                $this->currency = $obj->currency;
                $this->fk_soc = $obj->fk_soc;
                $this->fk_facture_fourn = $obj->fk_facture_fourn;
                $this->xml_content = $obj->xml_content;
                $this->pdf_filename = $obj->pdf_filename;
                $this->file_hash = $obj->file_hash;
                $this->status = $obj->status;
                $this->error_message = $obj->error_message;
                $this->date_creation = $this->db->jdate($obj->date_creation);
                $this->date_import = $this->db->jdate($obj->date_import);
                $this->tms = $this->db->jdate($obj->tms);
                $this->fk_user_creat = $obj->fk_user_creat;
                $this->fk_user_modif = $obj->fk_user_modif;
                $this->import_key = $obj->import_key;
                $this->entity = $obj->entity;

                $this->db->free($resql);
                return 1;
            } else {
                $this->db->free($resql);
                return 0;
            }
        } else {
            $this->error = $this->db->lasterror();
            return -1;
        }
    }

    /**
     * Update object in database
     *
     * @param User $user User that modifies
     * @param bool $notrigger false=launch triggers, true=disable triggers
     * @return int <0 if KO, >0 if OK
     */
    public function update($user, $notrigger = false)
    {
        $this->fk_user_modif = $user->id;

        $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element . " SET";
        $sql .= " ref = '" . $this->db->escape($this->ref) . "',";
        $sql .= " invoice_number = '" . $this->db->escape($this->invoice_number) . "',";
        $sql .= " invoice_date = " . ($this->invoice_date ? "'" . $this->db->idate($this->invoice_date) . "'" : "null") . ",";
        $sql .= " seller_name = '" . $this->db->escape($this->seller_name) . "',";
        $sql .= " seller_vat = '" . $this->db->escape($this->seller_vat) . "',";
        $sql .= " buyer_reference = '" . $this->db->escape($this->buyer_reference) . "',";
        $sql .= " total_ht = " . price2num($this->total_ht) . ",";
        $sql .= " total_ttc = " . price2num($this->total_ttc) . ",";
        $sql .= " currency = '" . $this->db->escape($this->currency) . "',";
        $sql .= " fk_soc = " . ($this->fk_soc > 0 ? (int) $this->fk_soc : "null") . ",";
        $sql .= " fk_facture_fourn = " . ($this->fk_facture_fourn > 0 ? (int) $this->fk_facture_fourn : "null") . ",";
        $sql .= " status = " . (int) $this->status . ",";
        $sql .= " date_import = " . ($this->date_import ? "'" . $this->db->idate($this->date_import) . "'" : "null") . ",";
        $sql .= " error_message = " . ($this->error_message ? "'" . $this->db->escape($this->error_message) . "'" : "null") . ",";
        $sql .= " fk_user_modif = " . (int) $this->fk_user_modif;
        $sql .= " WHERE rowid = " . (int) $this->id;

        dol_syslog(get_class($this) . "::update sql=" . $sql, LOG_DEBUG);
        $resql = $this->db->query($sql);

        if (!$resql) {
            $this->error = $this->db->lasterror();
            dol_syslog(get_class($this) . "::update error=" . $this->error, LOG_ERR);
            return -1;
        }

        return 1;
    }

    /**
     * Delete object from database
     *
     * @param User $user User that deletes
     * @param bool $notrigger false=launch triggers, true=disable triggers
     * @return int <0 if KO, >0 if OK
     */
    public function delete($user, $notrigger = false)
    {
        $sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element;
        $sql .= " WHERE rowid = " . (int) $this->id;

        dol_syslog(get_class($this) . "::delete", LOG_DEBUG);
        $resql = $this->db->query($sql);

        if (!$resql) {
            $this->error = $this->db->lasterror();
            return -1;
        }

        return 1;
    }

    /**
     * Check if file already imported (duplicate detection)
     *
     * @param string $file_hash SHA256 hash of file
     * @return bool true if already exists
     */
    public function isDuplicate($file_hash)
    {
        global $conf;

        $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . $this->table_element;
        $sql .= " WHERE file_hash = '" . $this->db->escape($file_hash) . "'";
        $sql .= " AND entity = " . (int) $conf->entity;

        $resql = $this->db->query($sql);
        if ($resql && $this->db->num_rows($resql) > 0) {
            return true;
        }

        return false;
    }

    /**
     * Get next reference number
     *
     * @return string
     */
    public function getNextRef()
    {
        global $conf;

        $sql = "SELECT MAX(CAST(SUBSTRING(ref, 4) AS UNSIGNED)) as maxref";
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
        $sql .= " WHERE ref LIKE 'ZI-%'";
        $sql .= " AND entity = " . (int) $conf->entity;

        $resql = $this->db->query($sql);
        if ($resql) {
            $obj = $this->db->fetch_object($resql);
            $num = $obj->maxref ? $obj->maxref + 1 : 1;
            return 'ZI-' . str_pad($num, 6, '0', STR_PAD_LEFT);
        }

        return 'ZI-000001';
    }

    /**
     * Normalize XML for database storage
     * Removes whitespace between tags to store compact XML
     *
     * @param string $xml XML content
     * @return string Normalized XML
     */
    public static function normalizeXml($xml)
    {
        if (empty($xml)) {
            return '';
        }

        $dom = new DOMDocument('1.0', 'UTF-8');
        $dom->preserveWhiteSpace = false;
        $dom->formatOutput = false;

        // Try to load XML
        if (@$dom->loadXML($xml)) {
            // Return compact XML without declaration
            $result = $dom->saveXML($dom->documentElement);
            return $result ? $result : $xml;
        }

        // Fallback: just remove whitespace between tags
        return preg_replace('/>\s+</', '><', trim($xml));
    }

    /**
     * Format XML for display
     * Takes compact XML and formats it with proper indentation
     *
     * @param string $xml Compact XML content
     * @return string Formatted XML
     */
    public static function formatXmlForDisplay($xml)
    {
        if (empty($xml)) {
            return '';
        }

        // Clean up any escaped newlines from old data (literal \n strings)
        $xml = str_replace('\n', '', $xml);
        $xml = str_replace('\r', '', $xml);
        $xml = str_replace('\t', '', $xml);

        $dom = new DOMDocument('1.0', 'UTF-8');
        $dom->preserveWhiteSpace = false;
        $dom->formatOutput = true;

        if (@$dom->loadXML($xml)) {
            return $dom->saveXML();
        }

        // Fallback: return as-is
        return $xml;
    }

    /**
     * Import a ZUGFeRD invoice from PDF file
     * This is the main entry point for batch/automated imports
     *
     * @param User $user User performing import
     * @param string $file_path Path to PDF file
     * @param bool $auto_create_invoice Whether to auto-create supplier invoice
     * @return int >0 (import ID) if OK, -2 if duplicate, <0 if error
     */
    public function importFromFile($user, $file_path, $auto_create_invoice = false)
    {
        global $conf, $langs;

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

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

        // Parse PDF
        $parser = new ZugferdParser($this->db);
        $result = $parser->extractFromPdf($file_path);
        if ($result < 0) {
            $this->error = $parser->error;
            return -1;
        }

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

        $invoice_data = $parser->getInvoiceData();

        // Check for duplicates
        $file_hash = $parser->getFileHash($file_path);
        if ($this->isDuplicate($file_hash)) {
            $this->error = $langs->trans('ErrorDuplicateInvoice');
            return -2; // Duplicate
        }

        // Find supplier
        $supplier_id = $this->findSupplier($invoice_data);

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

        // Create import record
        $import_id = $this->create($user);
        if ($import_id < 0) {
            return -3;
        }

        // Process and store line items
        $mapping = new ProductMapping($this->db);
        $unmatched_count = 0;
        $matched_count = 0;
        $total_lines = count($invoice_data['lines']);

        foreach ($invoice_data['lines'] as $line_data) {
            $line = new ImportLine($this->db);
            $line->fk_import = $import_id;
            $line->line_id = $line_data['line_id'];
            $line->supplier_ref = $line_data['product']['seller_id'];
            $line->product_name = $line_data['product']['name'];
            $line->description = $line_data['product']['description'];
            $line->quantity = $line_data['quantity'];
            $line->unit_code = $line_data['unit_code'];
            $line->unit_price = $line_data['unit_price'];
            $line->unit_price_raw = isset($line_data['unit_price_raw']) ? $line_data['unit_price_raw'] : $line_data['unit_price'];
            $line->basis_quantity = isset($line_data['basis_quantity']) ? $line_data['basis_quantity'] : 1;
            $line->basis_quantity_unit = isset($line_data['basis_quantity_unit']) ? $line_data['basis_quantity_unit'] : '';
            $line->line_total = $line_data['line_total'];
            $line->tax_percent = $line_data['tax_percent'];
            $line->ean = $line_data['product']['global_id'];

            // Copper surcharge (Kupferzuschlag) from ZUGFeRD - always set (0 if not present)
            if (isset($line_data['copper_surcharge']) && $line_data['copper_surcharge'] > 0) {
                $line->copper_surcharge = $line_data['copper_surcharge'];
                $line->copper_surcharge_basis_qty = isset($line_data['copper_surcharge_basis_qty']) ? $line_data['copper_surcharge_basis_qty'] : $line->basis_quantity;
            } else {
                $line->copper_surcharge = 0;
                $line->copper_surcharge_basis_qty = $line->basis_quantity;
            }

            // Try to match product
            $fk_product = 0;
            $match_method = '';

            if ($supplier_id > 0) {
                $match = $mapping->findProduct($supplier_id, $line_data['product']);
                if (!empty($match) && $match['fk_product'] > 0) {
                    $fk_product = $match['fk_product'];
                    $match_method = $match['method'];

                    // Update supplier price with EAN from invoice if empty
                    $invoiceEan = !empty($line_data['product']['global_id']) ? trim($line_data['product']['global_id']) : '';
                    $supplierRef = !empty($line_data['product']['seller_id']) ? $line_data['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)$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);
                    }
                }
            }

            $line->fk_product = $fk_product;
            $line->match_method = $match_method;

            if ($fk_product == 0) {
                $unmatched_count++;
            } else {
                $matched_count++;
            }

            $line->create($user);
        }

        // Determine status based on matching results
        // STATUS_IMPORTED only if: supplier found, has lines, and ALL lines have matched products
        if ($supplier_id == 0 || $total_lines == 0 || $unmatched_count > 0 || $matched_count == 0) {
            // Missing supplier, no lines, unmatched products, or no matches at all - needs manual intervention
            $this->status = self::STATUS_PENDING;
        } else {
            // All lines matched
            $this->status = self::STATUS_IMPORTED;
        }

        // Copy PDF to documents (in subfolder by import ID)
        $destdir = $conf->importzugferd->dir_output . '/imports/' . $this->id;
        if (!is_dir($destdir)) {
            dol_mkdir($destdir);
        }
        $destfile = $destdir . '/' . $this->pdf_filename;
        copy($file_path, $destfile);

        // Update status
        $this->update($user);

        // Send notification if manual intervention required
        if ($this->status == self::STATUS_PENDING && class_exists('ImportNotification')) {
            $notification = new ImportNotification($this->db);
            $importLine = new ImportLine($this->db);
            $storedLines = $importLine->fetchAllByImport($this->id);
            $notification->sendManualInterventionNotification($this, $storedLines);
        }

        return $import_id;
    }

    /**
     * Find supplier by buyer reference or VAT ID
     *
     * @param array $invoice_data Parsed invoice data
     * @return int Supplier ID or 0
     */
    protected 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;
    }

    /**
     * Get status label
     *
     * @param int $mode 0=short, 1=long
     * @return string
     */
    public function getLibStatut($mode = 0)
    {
        return $this->LibStatut($this->status, $mode);
    }

    /**
     * Return status label for a given status
     *
     * @param int $status Status
     * @param int $mode 0=short, 1=long
     * @return string
     */
    public function LibStatut($status, $mode = 0)
    {
        global $langs;

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

        $statusLabels = array(
            self::STATUS_IMPORTED => array('short' => 'Imported', 'long' => 'StatusImported', 'class' => 'status4'),
            self::STATUS_PROCESSED => array('short' => 'Processed', 'long' => 'StatusProcessed', 'class' => 'status6'),
            self::STATUS_ERROR => array('short' => 'Error', 'long' => 'StatusError', 'class' => 'status8'),
            self::STATUS_PENDING => array('short' => 'Pending', 'long' => 'StatusPending', 'class' => 'status1'),
        );

        $statusType = isset($statusLabels[$status]) ? $statusLabels[$status] : $statusLabels[0];
        $label = $mode == 0 ? $statusType['short'] : $statusType['long'];

        return dolGetStatus($langs->trans($label), '', '', $statusType['class']);
    }
}
