<?php
namespace PrestaShop\Module\LCVPrestaConnector;

use LCVPrestaConnector;

/**
 * Gestionnaire de produits connexes
 * 
 */
class MultipleProductsManager
{
    /**
     * Référence vers le module
     * 
     * @var LCVPrestaConnector
     */
    private LCVPrestaConnector $module;

    /**
     * Produits gérés
     * id_product => [
     *              'name' => string,
     *              'kinship' => array<int, int> (id_product/id_product)
     * ]
     * 
     * @var array<int, array>
     */
    private array $products = [];

    /**
     * Nouvelle instance du gestionnaire de produits connexes
     * 
     * @param LCVPrestaConnector $module Référence vers le module
     */
    public function __construct(LCVPrestaConnector $module)
    {
        $this->module = $module;
    }    

    /**
     * Ajoute un produit aux produits connexes à gérer pour cette session
     * 
     * @param int $product_id ID du produit à ajouter
     */
    public function addProduct(int $product_id)
    {
        $this->products[$product_id] = null;
    }

    /**
     * Chargement du cache
     */
    public function loadData()
    {
        // On parcours les informations à charger
        $load_products = [];
        foreach ($this->products as $product_id => $product_data)
        {
            if ($product_data === null)
                $load_products[$product_id] = '0';
        }

        if (count($load_products) == 0)
            return; // rien à charger !

        $id_supplier = $this->module->getCfg()->get(SyncConfiguration::CFG_SUPPLIER) ?? 0;

        // charger les informations ici depuis la base de données
        // nous allons charger la référence fournisseur des produits (ps_product_supplier)
        $db = \Db::getInstance();
        $sql = 'SELECT ps.`id_product`, ps.`product_supplier_reference`
                FROM `' . _DB_PREFIX_ . 'product_supplier` ps
                WHERE ps.`id_supplier` = ' . $id_supplier . ' AND ps.`id_product_attribute` = 0 AND ps.`id_product` IN (' . implode(',', array_keys($load_products)) . ')';
        $res = $db->executeS($sql);
        if ($res === FALSE)
            throw new \Exception('Erreur lors de la récupération des références fournisseur des produits : '.\Db::getInstance()->getMsgError());

        // On charge les références dans load_products
        foreach ($res as $row)
            $load_products[(int) $row['id_product']] = explode('|', $row['product_supplier_reference'])[0];

        // Maintenant que nous avons les références produits, nous allons charger tous les produits connexes
        // c'est à dire tous les produits dans ps_supplier_product qui ont la même référence fournisseur ou une référence fournisseur qui commence 
        // par la même référence suivi d'un pipe (|)
        $sql = 'SELECT ps.`id_product`, ps.`product_supplier_reference`, 
                pl.name as `name`,
                image_shop.`id_image`
                FROM `' . _DB_PREFIX_ . 'product_supplier` ps
                LEFT JOIN `' . _DB_PREFIX_ . 'product` p ON (p.id_product = ps.id_product)
                LEFT JOIN `' . _DB_PREFIX_ . 'product_shop` ph ON (ph.id_product = p.id_product AND ph.id_shop = ' . (int) \Context::getContext()->shop->id . ')
                LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON (pl.id_product = ps.id_product AND pl.id_lang = ' . (int) \Context::getContext()->language->id . ')                
                LEFT JOIN `' . _DB_PREFIX_ . 'image` i ON (i.id_product = ps.id_product)' . \Shop::addSqlAssociation('image', 'i', true, 'image_shop.cover = 1') . '
                WHERE p.`active` = 1 AND (p.`visibility` = \'both\' OR p.`visibility` = \'catalog\') AND ps.`id_supplier` = ' . $id_supplier . ' AND ps.`id_product_attribute` = 0 AND (';
        
        $first = true;
        foreach ($load_products as $product_id => $product_ref)
        {
            if ($first) $first = false; else $sql .= ' OR ';

            $sql .= '(ps.`product_supplier_reference` = \'' . $db->escape($product_ref) . '\' OR ps.`product_supplier_reference` LIKE \'' . $db->escape($product_ref) . '|%\')';
        }
        $sql .= ')';
        
        $res = $db->executeS($sql);
        if ($res === FALSE)
            throw new \Exception('Erreur lors de la récupération des produits connexes : '.\Db::getInstance()->getMsgError());

        // Association 'ref' => array<id_product>
        $associations = [];

        // Maintenant, on stocke dans la db
        foreach ($res as $row)
        {
            $product_id = (int) $row['id_product'];
            $product_name = $row['name'];
            $product_supplier_reference = explode('|', $row['product_supplier_reference'])[0];

            if (!isset($associations[$product_supplier_reference]))
                $associations[$product_supplier_reference] = [];
            $associations[$product_supplier_reference][] = $product_id;

            // on initialise le produit
            $this->products[$product_id] = [
                'name' => $product_name, 
                'id_image' => (int) ($row['id_image'] ?? 0),
                'lnk' => 'titi',
                'kinship' => []
            ];
        }

        // Enfin, dernière passe, on rempli les produits connexes selon les associations
        foreach ($associations as $id_products)
        {
            foreach ($id_products as $id_product)
                $this->products[$id_product]['kinship'] = $id_products;
        }
    }

    /**
     * Construit le sélecteur de produits connexes pour un produit spécifique
     * 
     * @param int $product_id ID du produit pour lequel construire le sélecteur
     * @return string Sélecteur HTML
     */
    public function buildSelector(int $product_id) : string
    {
        // Si product_id n'est pas déjà géré, on l'ajoute
        if (!isset($this->products[$product_id]))
            $this->addProduct($product_id);

        // On s'assure de charger les informations des produits
        $this->loadData();

        if (!isset($this->products[$product_id]))
            return ''; // produit non trouvé ou pas d'autre produit        

        $context = \Context::getContext();

        // Obtention du code iso de la langue actuelle
        $lang = $context->language->iso_code;

        // Format d'image.
        // Est-ce que le format de dimension d'image "selection" existe sur cette installation de prestashop
        $format = \Image::getSize('selection');
        $format = $format ? 'selection' : 'small_default';

        $selector = '';
        foreach ($this->products[$product_id]['kinship'] as $other_id)
        {
            $product = isset($this->products[$other_id]) ? $this->products[$other_id] : null;
            if (!$product)
                continue;

            $img = sprintf('<img itemprop="image" src="%s" title="%s" alt="%s" />',
                                    (isset($product['id_image']) && !empty($product['id_image'])) ? 
                                        $context->link->getImageLink($product['name'], $product['id_image'], $format) : 
                                        $context->link->getBaseLink()."img/p/".$lang."-default-".$format.".jpg",
                                    $product['name'],
                                    $product['name']
                            );

            if ($other_id == $product_id)
                $selector .= sprintf('<div class="active">%s</div>', $img);
            else            
                $selector .= sprintf('<a href="%s" title="%s">%s</a>',
                                    $context->link->getProductLink($other_id),
                                    $product['name'],
                                    $img
                            );
        }

        if ($selector)
            return $selector = '<div class="mpm_selector">' . $selector . '</div>';

        return '';
    }
}