<?php

/**
 * LolaCore - PlaybookRegistry
 *
 * In-memory index of playbooks loaded from all sources. Resolves slug
 * collisions using the same precedence as skills: filesystem > db >
 * addon > built_in.
 *
 * @package LolaCore
 * @license GPL-2.0-or-later
 */

declare(strict_types=1);

namespace LolaCore\Playbooks;

class PlaybookRegistry
{
    private PlaybookLoader $loader;

    /** @var array<string, Playbook> */
    private array $playbooks = [];

    private bool $built = false;

    public function __construct(PlaybookLoader $loader)
    {
        $this->loader = $loader;
    }

    public function build(): void
    {
        $this->playbooks = [];

        $result    = $this->loader->loadFromAllSources();
        $playbooks = is_array($result['playbooks'] ?? null) ? $result['playbooks'] : [];

        $bucketed = [
            Playbook::ORIGIN_BUILT_IN   => [],
            Playbook::ORIGIN_ADDON      => [],
            Playbook::ORIGIN_DB         => [],
            Playbook::ORIGIN_FILESYSTEM => [],
        ];

        foreach ($playbooks as $playbook) {
            $origin = $playbook->getOrigin();
            if (!isset($bucketed[$origin])) {
                continue;
            }
            $bucketed[$origin][] = $playbook;
        }

        foreach (
            [
                Playbook::ORIGIN_BUILT_IN,
                Playbook::ORIGIN_ADDON,
                Playbook::ORIGIN_DB,
                Playbook::ORIGIN_FILESYSTEM,
            ] as $origin
        ) {
            foreach ($bucketed[$origin] as $playbook) {
                $slug = $playbook->getSlug();
                if ($slug !== '') {
                    $this->playbooks[$slug] = $playbook;
                }
            }
        }

        $this->built = true;
    }

    /**
     * @return array<string, Playbook>
     */
    public function all(): array
    {
        if (!$this->built) {
            $this->build();
        }
        return $this->playbooks;
    }

    public function getBySlug(string $slug): ?Playbook
    {
        if (!$this->built) {
            $this->build();
        }
        return $this->playbooks[$slug] ?? null;
    }

    /**
     * @return array<int, Playbook>
     */
    public function getByDomain(string $domain): array
    {
        if (!$this->built) {
            $this->build();
        }
        return array_values(array_filter(
            $this->playbooks,
            static fn(Playbook $p) => $p->getDomain() === $domain
        ));
    }

    /**
     * @return array<int, Playbook>
     */
    public function getByAbilityPrefix(string $abilityId): array
    {
        if (!$this->built) {
            $this->build();
        }

        $matches = [];
        foreach ($this->playbooks as $playbook) {
            foreach ($playbook->getAbilityPrefixes() as $prefix) {
                if ($prefix !== '' && str_starts_with($abilityId, $prefix)) {
                    $matches[] = $playbook;
                    break;
                }
            }
        }

        return $matches;
    }
}
