<?php

namespace Myvetshop\Module\Clinique\Command\Click2Buy;

use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class GenerateCommand extends Command
{
    protected const QUERY_LIMIT = 500;

    protected EntityManagerInterface $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        parent::__construct('app:c2b:generate');

        $this->entityManager = $entityManager;
    }

    protected function configure(): void
    {
        $this->setDescription('Génère les fichiers nécessaires à Click2Buy (pour Virbac)');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // Création du dossier d'export
        $dir = $this->createDirIfNotExists();

        // Récupération de la connexion à la bdd
        $connection = $this->entityManager->getConnection();

        // Mise en place du context (nécessaire au calcul des prix)
        $context = \Context::getContext();
        \assert($context instanceof \Context);
        $context->currency = new \Currency(1, 1, 1);
        $context->country = new \Country(8, 1, 1);

        // Préparation des requêtes à exécuter
        $queries = [
            'stores' => 'SELECT'
                . ' c.code_privilege AS outlet_id'
                . ', c.name AS retailer_name'
                . ', c.name AS outlet_name'
                . ', TRIM(" - " FROM CONCAT(sl.address1, " - ", sl.address2)) AS address'
                . ', s.postcode AS zip_code'
                . ', s.city AS town'
                . ', co.iso_code AS country_code'
                . ', s.latitude AS latitude'
                . ', s.longitude AS longitude'
                . ', sl.hours AS open_hours'
                . ' FROM ps_myvetshop_clinique c'
                . ' INNER JOIN ps_store s ON s.id_store=c.id_store'
                . ' INNER JOIN ps_store_lang sl ON sl.id_store=s.id_store AND sl.id_lang=1'
                . ' INNER JOIN ps_country co ON co.id_country=s.id_country',
            'products' => 'SELECT'
                . ' pa.id_product_attribute AS product_id'
                . ', pa.ean13 AS ean'
                . ', TRIM(" ()" FROM CONCAT(pl.name, " (", COALESCE(GROUP_CONCAT(al.name SEPARATOR ", "), ""), ")") COLLATE utf8mb4_general_ci) AS product_name'
                . ', m.name AS brand'
                . ', p.id_product AS global_product_id'
                . ', i.id_image AS image_id'
                . ' FROM ps_product_attribute pa'
                . ' INNER JOIN ps_product_lang pl ON pl.id_product=pa.id_product AND pl.id_lang=1 AND pl.id_shop=1'
                . ' LEFT JOIN ps_product_attribute_combination pac ON pac.id_product_attribute=pa.id_product_attribute'
                . ' LEFT JOIN ps_attribute_lang al ON al.id_attribute=pac.id_attribute AND al.id_lang=1'
                . ' INNER JOIN ps_product p ON p.id_product=pa.id_product AND p.active=1'
                . ' INNER JOIN ps_manufacturer m ON m.id_manufacturer=p.id_manufacturer AND m.name LIKE "%virbac%"'
                . ' LEFT JOIN ps_image_shop i ON i.id_product=p.id_product AND i.cover=1'
                . ' GROUP BY pa.id_product_attribute',
            'store_products' => 'SELECT'
                . ' s.id_product_attribute AS product_id'
                . ', c.code_privilege AS outlet_id'
                . ', s.physical_quantity > 0 AS availability'
                . ', p.id_product AS global_product_id'
                . ' FROM ps_stock s'
                . ' INNER JOIN ps_myvetshop_clinique c ON c.id_warehouse=s.id_warehouse'
                . ' INNER JOIN ps_product_attribute pa ON pa.id_product_attribute=s.id_product_attribute'
                . ' INNER JOIN ps_product p ON p.id_product=pa.id_product AND p.active=1'
                . ' INNER JOIN ps_manufacturer m ON m.id_manufacturer=p.id_manufacturer AND m.name LIKE "%virbac%"',
        ];

        // Execution des requêtes avec pagination et éventuellement un traitement sur les données
        foreach ($queries as $name => $query) {
            // Gestion de la pagination
            $count = $connection->executeQuery(\sprintf('SELECT COUNT(*) FROM(%s) t', $query))->fetchColumn();
            if (!\is_numeric($count)) {
                $output->writeln(\sprintf('Missing data for %s ', $name));
                continue;
            }
            $pages = \ceil((int) $count / self::QUERY_LIMIT);
            $stream = \fopen($dir . '/' . $name . '.csv', 'w');
            if (!$stream) {
                $output->writeln(\sprintf('Cannot open the %s file', $name));
                continue;
            }

            // Execution des requêtes pour chaque page
            $addHeaders = true;
            for ($i = 1; $i <= $pages; ++$i) {
                $offset = ($i - 1) * self::QUERY_LIMIT;
                $finalQuery = $query . ' LIMIT ' . self::QUERY_LIMIT . ' OFFSET ' . $offset;
                foreach ($connection->executeQuery($finalQuery)->fetchAll() as $row) {
                    \assert(\is_array($row));

                    switch ($name) {
                        case 'products':
                            // Pour les produits, il faut calculer les urls et prix
                            $product = new \Product($row['global_product_id'], false, 1, 1);

                            $row['image'] = $row['image_id'] ? (new \Link())->getImageLink(
                                \is_array($product->link_rewrite) ? ($product->link_rewrite[0] ?? '') : $product->link_rewrite,
                                $row['image_id'],
                                'home_default',
                            ) : null;
                            !$row['image'] || \strpos($row['image'], 'http') === 0 ?: $row['image'] = 'https://' . $row['image'];
                            $row['url'] = (new \Link())->getProductLink($product);
                            // @phpstan-ignore-next-line
                            $row['price'] = \Product::computeTarifPrivilege($product->id, $row['product_id']);

                            unset($row['global_product_id']);
                            unset($row['image_id']);
                            break;
                        case 'store_products':
                            // Pour les associations produit-clinique, il faut calculer les prix
                            // @phpstan-ignore-next-line
                            $row['price'] = \Product::computeTarifPrivilege($row['global_product_id'], $row['product_id']);
                            unset($row['global_product_id']);
                    }

                    if ($addHeaders) {
                        \fputcsv($stream, \array_keys($row));
                    }
                    $addHeaders = false;

                    \fputcsv($stream, $row);
                }
            }
            \fclose($stream);
        }

        return 0;
    }

    protected function createDirIfNotExists(): string
    {
        $dir = _PS_ROOT_DIR_ . '/Click2Buy';
        if (!\is_dir($dir)) {
            \mkdir($dir);
        }

        $indexPath = $dir . '/index.php';
        $htaccessPath = $dir . '/.htaccess';
        $htpasswdPath = $dir . '/.htpasswd';

        // Création d'un index.php pour éviter le listing
        if (!\file_exists($indexPath)) {
            \file_put_contents($indexPath, '');
        }

        // Création d'un htaccess pour limiter l'accès
        if (!\file_exists($htaccessPath)) {
            $stream = \fopen($htaccessPath, 'w');
            if (!$stream) {
                throw new \LogicException('Cannot open the htaccess file');
            }

            \fwrite($stream, 'AuthType Basic' . "\n");
            \fwrite($stream, 'AuthName "Accès protégé"' . "\n");
            \fwrite($stream, 'AuthUserFile ' . $dir . '/.htpasswd' . "\n");
            \fwrite($stream, 'require valid-user' . "\n");
            \fclose($stream);
        }

        // Création d'un htpasswd pour définir les accès
        if (!\file_exists($htpasswdPath)) {
            \file_put_contents($htpasswdPath, 'c2b:$apr1$0641a7gp$HytFbulVG05Cm8Oo6fTzJ/');
        }

        return $dir;
    }
}
