<?php

declare(strict_types=1);

namespace App\Service;

use App\Model\Route;
use Hyperf\HttpServer\Router\DispatcherFactory;
use Hyperf\HttpServer\Router\Handler;
use Hyperf\HttpServer\Router\RouteCollector;
use Psr\Container\ContainerInterface;

class RouteSyncService
{
    public function __construct(
        protected readonly ContainerInterface $container,
    ) {}

    /**
     * 同步 Hyperf 注解路由到 routes 表
     *
     * @return array{synced: int, total: int}
     */
    public function sync(): array
    {
        $factory = $this->container->get(DispatcherFactory::class);
        $router = $factory->getRouter('http');
        $routes = $this->extractRoutes($router);

        $synced = 0;
        foreach ($routes as $route_info) {
            Route::query()->updateOrCreate(
                ['method' => $route_info['method'], 'path' => $route_info['path']],
                ['name' => $route_info['name']]
            );
            $synced++;
        }

        return [
            'synced' => $synced,
            'total' => count($routes),
        ];
    }

    /**
     * 从路由收集器中提取所有 API 路由
     *
     * @return array<int, array{method: string, path: string, name: string|null}>
     */
    private function extractRoutes(RouteCollector $router): array
    {
        $routes = [];
        [$staticRouters, $variableRouters] = $router->getData();

        // 静态路由（无路径参数）
        foreach ($staticRouters as $method => $items) {
            foreach ($items as $handler) {
                $this->collectRoute($routes, $method, $handler);
            }
        }

        // 动态路由（含路径参数如 {id}）
        foreach ($variableRouters as $method => $items) {
            foreach ($items as $item) {
                if (is_array($item['routeMap'] ?? false)) {
                    foreach ($item['routeMap'] as $routeMap) {
                        $this->collectRoute($routes, $method, $routeMap[0]);
                    }
                }
            }
        }

        return array_values($routes);
    }

    /**
     * 收集单条路由信息，仅同步 /api/ 前缀的路由
     */
    private function collectRoute(array &$routes, string $method, Handler $handler): void
    {
        $path = $handler->route;

        // 仅同步 API 路由
        if (!str_starts_with($path, '/api/')) {
            return;
        }

        // 解析 action 名称
        $name = null;
        if (is_array($handler->callback)) {
            $name = $handler->callback[0] . '::' . $handler->callback[1];
        } elseif (is_string($handler->callback)) {
            $name = $handler->callback;
        }

        $key = $method . '|' . $path;
        if (!isset($routes[$key])) {
            $routes[$key] = [
                'method' => $method,
                'path' => $path,
                'name' => $name,
            ];
        }
    }
}
