<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\EventListener;

use Ferienpass\CoreBundle\Repository\TenantRepository;
use Ferienpass\CoreBundle\Tenant\TenantContext;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

/**
 * Gives every console command a `--tenant=<slug>` option (also readable from
 * the `FERIENPASS_TENANT` environment variable), so cron jobs and one-off
 * maintenance can run inside one municipality:
 *
 *     bin/console ferienpass:cron:send-reminders --tenant=nordhorn
 *
 * Without it a command runs unfiltered, across all tenants — right for
 * `contao:migrate` or `cache:clear`, wrong for anything that touches tenant
 * data, so pass the option there.
 *
 * The option is registered on the command rather than pre-declared globally
 * because it has to exist on commands the bundle does not own. Symfony binds
 * the input after this event, so adding it here is in time; the value itself is
 * read straight off the raw tokens, which works before binding.
 */
#[AsEventListener(event: ConsoleEvents::COMMAND, priority: 1024)]
class TenantConsoleListener
{
    public function __construct(
        private readonly TenantContext $tenantContext,
        private readonly TenantRepository $tenants,
    ) {
    }

    public function __invoke(ConsoleCommandEvent $event): void
    {
        if (!$this->tenantContext->isEnabled()) {
            return;
        }

        $command = $event->getCommand();
        if (null !== $command && !$command->getDefinition()->hasOption('tenant')) {
            $command->addOption('tenant', null, InputOption::VALUE_REQUIRED, 'Run inside one tenant (its slug). Omit to run across all tenants.');
        }

        $slug = $event->getInput()->getParameterOption(['--tenant'], null, true);
        $slug ??= $_SERVER['FERIENPASS_TENANT'] ?? $_ENV['FERIENPASS_TENANT'] ?? null;

        if (!\is_string($slug) || '' === $slug) {
            return;
        }

        $tenant = $this->tenants->findOneBySlug($slug);
        if (null === $tenant) {
            throw new \RuntimeException(\sprintf('Unknown tenant "%s". Run "ferienpass:tenant:list" to see the tenants of this installation.', $slug));
        }

        $this->tenantContext->setTenant($tenant);
    }
}
