<?php
declare(strict_types=1);

namespace PpPhp\Core\Designer\Toolbox;

use PpPhp\Core\Designer\Component\DesignerComponentRuntime;

final class DesignerToolboxRuntime
{
    public function __construct(private readonly DesignerComponentRuntime $components = new DesignerComponentRuntime()) {}

    public function build(array $state = []): array
    {
        $toolboxState = DesignerToolboxState::fromArray($state);
        $registry = $this->components->registry()->toArray();

        $groups = [];
        foreach ((array) ($registry['categories'] ?? []) as $category) {
            $groups[$category['categoryId']] = DesignerToolboxGroup::create(
                (string) $category['categoryId'],
                (string) $category['label'],
                (string) ($category['icon'] ?? ''),
                [],
                (int) ($category['order'] ?? 100)
            );
        }

        foreach ((array) ($registry['components'] ?? []) as $component) {
            $item = DesignerToolboxItem::fromComponent(
                $component,
                $toolboxState->isFavorite((string) ($component['type'] ?? '')),
                $toolboxState->recentRank((string) ($component['type'] ?? ''))
            );

            if (!$item->matches($toolboxState->query())) {
                continue;
            }

            $category = $item->category();
            if (!isset($groups[$category])) {
                $groups[$category] = DesignerToolboxGroup::create($category, ucfirst($category));
            }
            $groups[$category] = $groups[$category]->withItem($item);
        }

        $groupRows = array_values(array_filter(
            array_map(static fn (DesignerToolboxGroup $group): array => $group->toArray(), $groups),
            static fn (array $group): bool => count($group['items'] ?? []) > 0
        ));

        usort($groupRows, static fn (array $a, array $b): int => ((int) ($a['order'] ?? 100)) <=> ((int) ($b['order'] ?? 100)));

        return [
            'state' => $toolboxState->toArray(),
            'groups' => $groupRows,
            'summary' => [
                'groups' => count($groupRows),
                'items' => array_sum(array_map(static fn (array $group): int => count($group['items'] ?? []), $groupRows)),
                'favorites' => count($toolboxState->favorites()),
                'recent' => count($toolboxState->recent()),
                'query' => $toolboxState->query(),
            ],
        ];
    }

    public function favorites(array $state = []): array
    {
        $toolbox = $this->build($state);
        $items = [];
        foreach ($toolbox['groups'] as $group) {
            foreach ($group['items'] as $item) {
                if (($item['favorite'] ?? false) === true) {
                    $items[] = $item;
                }
            }
        }

        return $items;
    }

    public function recent(array $state = []): array
    {
        $toolbox = $this->build($state);
        $items = [];
        foreach ($toolbox['groups'] as $group) {
            foreach ($group['items'] as $item) {
                if ((int) ($item['recentRank'] ?? 0) > 0) {
                    $items[] = $item;
                }
            }
        }

        usort($items, static fn (array $a, array $b): int => ((int) ($b['recentRank'] ?? 0)) <=> ((int) ($a['recentRank'] ?? 0)));
        return $items;
    }

    public function pluginDiscovery(array $pluginComponents = []): array
    {
        $discovered = [];
        foreach ($pluginComponents as $component) {
            if (!is_array($component)) {
                continue;
            }
            $discovered[] = [
                'type' => (string) ($component['type'] ?? ''),
                'title' => (string) ($component['title'] ?? ''),
                'plugin' => (string) ($component['plugin'] ?? 'local'),
                'status' => (($component['type'] ?? '') !== '' && ($component['title'] ?? '') !== '') ? 'valid' : 'invalid',
            ];
        }

        return [
            'plugins' => $discovered,
            'valid' => count(array_filter($discovered, static fn (array $row): bool => ($row['status'] ?? '') === 'valid')),
            'invalid' => count(array_filter($discovered, static fn (array $row): bool => ($row['status'] ?? '') === 'invalid')),
        ];
    }
}
