<?php

declare(strict_types=1);

namespace App\Providers;

use hg\apidoc\utils\AutoRegisterRouts;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;

final class ApidocRouteServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        $config = config('apidoc');
        $config['auto_register_routes'] = true;

        foreach ((new AutoRegisterRouts($config))->getAppsApis() as $controller) {
            $classMiddleware = $this->normalizeMiddleware($controller['middleware'] ?? []);

            foreach ($controller['methods'] ?? [] as $method) {
                $middleware = array_values(array_unique(array_merge(
                    $classMiddleware,
                    $this->normalizeMiddleware($method['middleware'] ?? []),
                )));

                $route = Route::match(
                    $this->normalizeMethods($method['method'] ?? 'GET'),
                    $method['url'],
                    '\\'.$method['controller'].'@'.$method['name'],
                );

                if ($middleware !== []) {
                    $route->middleware($middleware);
                }
            }
        }
    }

    /**
     * @return array<int, string>
     */
    private function normalizeMethods(mixed $method): array
    {
        if (is_string($method)) {
            return array_values(array_filter(array_map('trim', explode(',', strtoupper($method)))));
        }

        if (is_array($method)) {
            $value = $method['name'] ?? $method;

            if (is_string($value)) {
                return $this->normalizeMethods($value);
            }

            if (is_array($value)) {
                return array_values(array_filter(array_map(
                    fn (mixed $item): string => strtoupper((string) $item),
                    $value,
                )));
            }
        }

        return ['GET'];
    }

    /**
     * @return array<int, string>
     */
    private function normalizeMiddleware(mixed $middleware): array
    {
        if (is_string($middleware)) {
            return [$middleware];
        }

        if (! is_array($middleware)) {
            return [];
        }

        $value = $middleware['name'] ?? $middleware;
        if (is_string($value)) {
            return [$value];
        }

        if (! is_array($value)) {
            return [];
        }

        return array_values(array_filter(array_map(
            fn (mixed $item): string => (string) $item,
            $value,
        )));
    }
}
