<?php

namespace Myvetshop\Module\Clinique\Command\Clinic;

use Doctrine\ORM\EntityManagerInterface;
use Myvetshop\Module\Clinique\Entity\EstablishmentEvent;
use Myvetshop\Module\Clinique\Entity\Factory\EstablishmentEventFactory;
use Myvetshop\Module\Clinique\Entity\MyvetshopClinique;
use Myvetshop\Module\Clinique\Repository\MyvetshopCliniqueRepository;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class ClinicEventBootstrapCommand extends Command
{
    protected \Db $db;

    private EntityManagerInterface $em;

    private EstablishmentEventFactory $establishmentEventFactory;

    private MyvetshopCliniqueRepository $myvetshopCliniqueRepository;

    protected function configure(): void
    {
        $this
            ->setDescription("Pré-rempli les événements d'une clinique")
            ->addArgument(
                'code_privilege',
                InputArgument::REQUIRED,
                'Code privilège de la clinique'
            )
            ->addOption(
                'backward-limit',
                null,
                InputOption::VALUE_REQUIRED,
                'Nombre de jours en arrière à prendre en compte',
                '-3 months'
            );
    }

    public function __construct(
        \Db $db,
        EntityManagerInterface $em,
        EstablishmentEventFactory $establishmentEventFactory,
        MyvetshopCliniqueRepository $myvetshopCliniqueRepository
    ) {
        $this->db = $db;
        $this->em = $em;
        $this->establishmentEventFactory = $establishmentEventFactory;
        $this->myvetshopCliniqueRepository = $myvetshopCliniqueRepository;

        parent::__construct('app:clinic:events-bootstrap');
    }

    public function execute(InputInterface $input, OutputInterface $output): int
    {
        \Module::getInstanceByName('myvetshopclinique');
        \Cache::setInstanceForTesting(new \NoOpCache());
        $this->db->disableCache();

        $styledOutput = new SymfonyStyle($input, $output);

        $codePrivilege = $input->getArgument('code_privilege');
        $backwardLimit = $input->getOption('backward-limit');
        if (!\is_string($codePrivilege) || !\is_string($backwardLimit)) {
            $styledOutput->error('Options invalides');

            return 1;
        }

        $clinic = $this->myvetshopCliniqueRepository->findByCodePrivilege($codePrivilege);

        if (null === $clinic) {
            $styledOutput->error('Clinique non trouvée');

            return 1;
        }

        try {
            $backwardLimit = new \DateTimeImmutable($backwardLimit);
        } catch (\Exception $e) {
            $styledOutput->error($e->getMessage());

            return 1;
        }

        $styledOutput->title('Pré-remplissage des événements de la clinique ' . $clinic->codePrivilege);

        $styledOutput->section('Clients actuels');
        $customerIds = $this->bootstrapActualCustomerEvents($clinic);
        $this->em->flush();

        $styledOutput->section('Clients ayant commandé dans la période d\'import');
        $this->bootstrapOrderCustomerEvents($clinic, $backwardLimit, $customerIds);
        $this->em->flush();

        $styledOutput->section('Commandes dans la période d\'import');
        $this->bootstrapOrderEvents($clinic, $backwardLimit);
        $this->em->flush();

        return 0;
    }

    /**
     * @return array<int, int>
     */
    private function bootstrapActualCustomerEvents(MyvetshopClinique $clinic): array
    {
        $groups = [
            (int) $clinic->idGroup,
        ];
        if ($clinic->rurale) {
            $groups[] = (int) $clinic->idGroupRural;
        }

        $customers = $this->db->query(
            'SELECT *'
            . ' FROM ' . _DB_PREFIX_ . 'customer'
            . ' WHERE id_default_group IN (' . \implode(',', $groups) . ') AND deleted = 0'
        );
        if (!$customers) {
            throw new \Exception("Erreur lors de la récupération des clients de la clinique {$clinic->codePrivilege}");
        }

        $ret = [];

        while ($row = $this->db->nextRow($customers)) {
            if (!\is_array($row)) {
                continue;
            }

            $customer = new \Customer();
            $customer->hydrate($row);

            $ret[(int) $customer->id] = (int) $customer->id;

            $event = $this->establishmentEventFactory->createCustomerEvent(
                EstablishmentEvent::EVENT_CUSTOMER_JOIN,
                $customer
            );
            $event->dateAdd = new \DateTimeImmutable($customer->date_add);

            $this->em->persist($event);
        }

        return $ret;
    }

    /**
     * @param array<int, int> $customerIds
     */
    private function bootstrapOrderCustomerEvents(
        MyvetshopClinique $clinic,
        \DateTimeImmutable $backwardLimit,
        array $customerIds): void
    {
        $carrierIds = [
            (int) $clinic->idCarrier,
            (int) $clinic->idCarrierHome,
        ];

        $customers = $this->db->query(
            'SELECT DISTINCT ' . _DB_PREFIX_ . 'customer.*'
            . ' FROM ' . _DB_PREFIX_ . 'customer'
            . ' INNER JOIN ' . _DB_PREFIX_ . 'orders ON ' . _DB_PREFIX_ . 'customer.id_customer = ' . _DB_PREFIX_ . 'orders.id_customer'
            . ' WHERE ' . _DB_PREFIX_ . 'orders.id_carrier IN (' . \implode(',', $carrierIds) . ')'
            . ' AND ' . _DB_PREFIX_ . 'orders.date_add >= "' . $this->db->escape($backwardLimit->format('Y-m-d H:i:s')) . '"'
            . (!empty($customerIds) ? ' AND ' . _DB_PREFIX_ . 'customer.id_customer NOT IN (' . \implode(',', $customerIds) . ')' : '')
        );

        if (!$customers) {
            throw new \Exception("Erreur lors de la récupération des clients de la clinique {$clinic->codePrivilege}");
        }

        while ($row = $this->db->nextRow($customers)) {
            if (!\is_array($row)) {
                continue;
            }

            $customer = new \Customer();
            $customer->hydrate($row);

            $event = $this->establishmentEventFactory->createCustomerEvent(
                EstablishmentEvent::EVENT_CUSTOMER_JOIN,
                $customer
            );
            $event->dateAdd = new \DateTimeImmutable($customer->date_add);

            $this->em->persist($event);
        }
    }

    private function bootstrapOrderEvents(MyvetshopClinique $clinic, \DateTimeImmutable $backwardLimit): void
    {
        $carrierIds = [
            (int) $clinic->idCarrier,
            (int) $clinic->idCarrierHome,
        ];

        $orders = $this->db->query(
            'SELECT id_order'
            . ' FROM ' . _DB_PREFIX_ . 'orders'
            . ' WHERE ' . _DB_PREFIX_ . 'orders.id_carrier IN (' . \implode(',', $carrierIds) . ')'
            . ' AND ' . _DB_PREFIX_ . 'orders.date_add >= "' . $this->db->escape($backwardLimit->format('Y-m-d H:i:s')) . '"'
        );

        if (!$orders) {
            throw new \Exception("Erreur lors de la récupération des commandes de la clinique {$clinic->codePrivilege}");
        }

        while ($row = $this->db->nextRow($orders)) {
            if (!\is_array($row)) {
                continue;
            }

            $order = new \Order($row['id_order']);

            $event = $this->establishmentEventFactory->createOrderEvent(
                EstablishmentEvent::EVENT_ORDER_UPDATED,
                $order
            );
            $event->dateAdd = new \DateTimeImmutable($order->date_upd);

            $this->em->persist($event);
        }
    }
}
