<?php

declare(strict_types=1);

namespace App\Service;

use App\Entity\Ecole;
use App\Entity\TenantDomain;

final class PublicUrlGenerator
{
    public function __construct(
        private readonly string $publicDomain = 'localhost',
        private readonly string $adminHost = 'localhost',
        private readonly string $scheme = 'http',
    ) {
    }

    public function schoolUrl(Ecole $ecole): string
    {
        return $this->baseUrl($ecole).'/';
    }

    public function registrationUrl(Ecole $ecole): string
    {
        return $this->baseUrl($ecole).'/inscription';
    }

    public function confirmationUrl(Ecole $ecole, string $numeroDossier): string
    {
        return $this->baseUrl($ecole).'/inscription/confirmation/'.rawurlencode($numeroDossier);
    }

    public function oldStudentsSearchUrl(Ecole $ecole): string
    {
        return $this->baseUrl($ecole).'/anciens-etudiants';
    }

    public function platformUrl(string $path = '/'): string
    {
        return $this->urlForHost($this->platformHost(), $path);
    }

    public function absoluteAssetUrl(?Ecole $ecole, ?string $path): string
    {
        $path = trim((string) $path);
        if ($path === '') {
            $path = 'assets/brand/logo-salmad-dark.png';
        }

        if (preg_match('#^https?://#i', $path) === 1) {
            return $path;
        }

        $baseUrl = $ecole instanceof Ecole ? $this->baseUrl($ecole) : $this->platformUrl();

        return rtrim($baseUrl, '/').'/'.ltrim($path, '/');
    }

    private function baseUrl(Ecole $ecole): string
    {
        $scheme = trim($this->scheme) ?: 'http';
        $publicDomain = trim($this->publicDomain);
        $canonicalHost = $this->cleanHost($ecole->getCanonicalTenantDomain()?->getHost());

        // Public links must always point to the canonical domain; aliases are only accepted for inbound legacy traffic.
        if ($canonicalHost !== null) {
            return sprintf('%s://%s', $scheme, $canonicalHost);
        }

        $subdomain = $this->cleanHostPart($ecole->getSousDomaine());

        if ($subdomain && $publicDomain !== '') {
            return sprintf('%s://%s.%s', $scheme, $subdomain, trim($publicDomain, '/'));
        }

        $host = trim($this->adminHost) ?: trim($this->publicDomain) ?: 'localhost';
        $slug = $this->cleanPathPart($ecole->getSlug() ?: (string) $ecole->getId());

        return sprintf('%s://%s/madrassas/%s', $scheme, trim($host, '/'), $slug);
    }

    private function urlForHost(string $host, string $path = '/'): string
    {
        $scheme = trim($this->scheme) ?: 'http';
        $path = '/'.ltrim($path, '/');

        return sprintf('%s://%s%s', $scheme, $host, $path);
    }

    private function platformHost(): string
    {
        return $this->cleanHost($this->adminHost)
            ?? $this->cleanHost($this->publicDomain)
            ?? 'localhost';
    }

    private function cleanHostPart(?string $value): ?string
    {
        $value = $value !== null ? mb_strtolower(trim($value)) : null;
        $value = $value ? preg_replace('/[^a-z0-9-]+/', '-', $value) : null;
        $value = $value ? trim($value, '-') : null;

        return $value !== '' ? $value : null;
    }

    private function cleanHost(?string $value): ?string
    {
        $value = $value !== null ? TenantDomain::normalizeHost($value) : null;

        return $value !== '' ? $value : null;
    }

    private function cleanPathPart(string $value): string
    {
        return trim(preg_replace('/[^a-zA-Z0-9-]+/', '-', $value) ?: 'madrassa', '-');
    }
}
