<?php

declare(strict_types=1);

namespace App\Support\Seo;

use Illuminate\Support\Collection;

final class BreadcrumbTrail
{
    /**
     * @param  iterable<mixed>|Collection<int, mixed>|null  $breadcrumbs
     * @return list<array{name: string, url: string}>
     */
    public static function normalize(iterable|Collection|null $breadcrumbs): array
    {
        $items = collect($breadcrumbs instanceof Collection ? $breadcrumbs->all() : ($breadcrumbs ?? []))
            ->map(fn (mixed $crumb): ?array => self::mapCrumb($crumb))
            ->filter(fn (?array $crumb): bool => is_array($crumb) && $crumb['name'] !== '' && $crumb['url'] !== '')
            ->values();

        $home = [
            'name' => 'Home',
            'url' => self::absoluteUrl('/'),
        ];

        $normalized = [];
        $seen = [];

        foreach ($items as $crumb) {
            $name = trim((string) ($crumb['name'] ?? ''));
            $url = self::absoluteUrl((string) ($crumb['url'] ?? ''));

            if ($name === '' || $url === '') {
                continue;
            }

            if (self::isHome($name, $url)) {
                $name = $home['name'];
                $url = $home['url'];
            }

            $key = strtolower($name) . '|' . rtrim(strtolower($url), '/');
            if (isset($seen[$key])) {
                continue;
            }

            $seen[$key] = true;
            $normalized[] = ['name' => $name, 'url' => $url];
        }

        if ($normalized === [] || ! self::isHome($normalized[0]['name'], $normalized[0]['url'])) {
            array_unshift($normalized, $home);
        }

        return array_values($normalized);
    }

    /**
     * @param  mixed  $crumb
     * @return array{name: string, url: string}|null
     */
    private static function mapCrumb(mixed $crumb): ?array
    {
        if (is_array($crumb)) {
            return [
                'name' => trim((string) ($crumb['name'] ?? '')),
                'url' => trim((string) ($crumb['url'] ?? '')),
            ];
        }

        if (is_object($crumb)) {
            return [
                'name' => trim((string) ($crumb->name ?? '')),
                'url' => trim((string) ($crumb->url ?? '')),
            ];
        }

        return null;
    }

    private static function isHome(string $name, string $url): bool
    {
        $normalizedUrl = rtrim(strtolower($url), '/');
        $homeUrl = rtrim(strtolower(self::absoluteUrl('/')), '/');

        return strtolower($name) === 'home' || $normalizedUrl === $homeUrl;
    }

    private static function absoluteUrl(string $url): string
    {
        $trimmed = trim($url);
        if ($trimmed === '') {
            return '';
        }

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

        return url($trimmed);
    }
}