<?php

/**
 * Chill is a software for social workers.
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\CalendarBundle\RemoteCalendar\DependencyInjection;

use Chill\CalendarBundle\Command\AzureGrantAdminConsentAndAcquireToken;
use Chill\CalendarBundle\Command\MapAndSubscribeUserCalendarCommand;
use Chill\CalendarBundle\Controller\RemoteCalendarConnectAzureController;
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MachineHttpClient;
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MachineTokenStorage;
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MSUserAbsenceReaderInterface;
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MSUserAbsenceSync;
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraphRemoteCalendarConnector;
use Chill\CalendarBundle\RemoteCalendar\Connector\NullRemoteCalendarConnector;
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use TheNetworg\OAuth2\Client\Provider\Azure;

class RemoteCalendarCompilerPass implements CompilerPassInterface
{
    private const ZIMBRA_CONNECTOR = 'Chill\ZimbraBundle\Calendar\Connector\ZimbraConnector';

    private const MS_GRAPH_SERVICES_TO_REMOVE = [
        MapAndSubscribeUserCalendarCommand::class,
        AzureGrantAdminConsentAndAcquireToken::class,
        RemoteCalendarConnectAzureController::class,
        MachineTokenStorage::class,
        MachineHttpClient::class,
        MSGraphRemoteCalendarConnector::class,
        MSUserAbsenceReaderInterface::class,
        MSUserAbsenceSync::class,
    ];

    public function process(ContainerBuilder $container)
    {
        $config = $container->getParameter('chill_calendar.remote_calendar_dsn');
        if (true === $container->getParameter('chill_calendar')['remote_calendars_sync']['microsoft_graph']['enabled']) {
            $dsn = 'msgraph://default';
        } else {
            $dsn = $config;
        }

        $scheme = parse_url($dsn, PHP_URL_SCHEME);

        if ('msgraph' === $scheme) {
            $connector = MSGraphRemoteCalendarConnector::class;

            $container->setAlias(HttpClientInterface::class.' $machineHttpClient', MachineHttpClient::class);
        } elseif ('zimbra+http' === $scheme || 'zimbra+https' === $scheme) {
            $connector = self::ZIMBRA_CONNECTOR;
            foreach (self::MS_GRAPH_SERVICES_TO_REMOVE as $serviceId) {
                $container->removeDefinition($serviceId);
            }
        } elseif ('null' === $scheme) {
            $connector = NullRemoteCalendarConnector::class;
            foreach (self::MS_GRAPH_SERVICES_TO_REMOVE as $serviceId) {
                $container->removeDefinition($serviceId);
            }
        } else {
            throw new \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException('Unsupported remote calendar scheme: '.$scheme);
        }

        if (!$container->hasAlias(Azure::class) && $container->hasDefinition('knpu.oauth2.client.azure')) {
            $container->setAlias(Azure::class, 'knpu.oauth2.provider.azure');
        }

        foreach ([
            NullRemoteCalendarConnector::class,
            MSGraphRemoteCalendarConnector::class,
            self::ZIMBRA_CONNECTOR,
        ] as $serviceId) {
            if ($connector === $serviceId) {
                $container->getDefinition($serviceId)
                    ->setDecoratedService(RemoteCalendarConnectorInterface::class);
            } else {
                // keep the container lighter by removing definitions
                if ($container->hasDefinition($serviceId)) {
                    $container->removeDefinition($serviceId);
                }
            }
        }
    }
}
