<?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\Tenant;

use Ferienpass\CoreBundle\Entity\TenantDomain;
use Ferienpass\CoreBundle\Repository\TenantDomainRepository;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

/**
 * Turns a request host into the tenant it belongs to and the surface it serves.
 *
 * Fail-closed by design: a host that no enabled tenant claims (and that is not
 * the platform console) resolves to null, and the caller must answer 404 rather
 * than fall back to a default tenant.
 */
class HostResolver
{
    public function __construct(
        private readonly TenantDomainRepository $domains,
        #[Autowire(param: 'ferienpass.multi_tenancy.enabled')]
        private readonly bool $enabled = false,
        #[Autowire(param: 'ferienpass.multi_tenancy.platform_host')]
        private readonly ?string $platformHost = null,
    ) {
    }

    public function isEnabled(): bool
    {
        return $this->enabled;
    }

    public function platformHost(): ?string
    {
        return null === $this->platformHost ? null : TenantDomain::normalizeHost($this->platformHost);
    }

    public function resolve(string $host): ?ResolvedHost
    {
        $host = TenantDomain::normalizeHost($host);

        // Single-tenant build: every host is the one host, and it serves what
        // it always served.
        if (!$this->enabled) {
            return ResolvedHost::untenanted($host);
        }

        if ('' === $host) {
            return null;
        }

        if ($host === $this->platformHost()) {
            return ResolvedHost::platform($host);
        }

        $domain = $this->domains->findOneByHost($host);
        if (null === $domain || null === $tenant = $domain->getTenant()) {
            return null;
        }

        if ($domain->isAdmin()) {
            return ResolvedHost::admin($host, $tenant);
        }

        return ResolvedHost::frontend($host, $tenant, !$tenant->hasDedicatedAdminHost());
    }
}
