<?php

declare(strict_types=1);

/**
 * APO-194 Card 7 — GET /api/v1/design/definitions
 *
 * APO-205 Card 1: exposeToMcp flipped from false → true. Read-only enumeration of
 * design definitions and packaged archetypes is an ordinary operator-visible state
 * read; the prior install-management framing conflated reads with the mutating
 * apply/import/save/remove actions. Identity-enumeration and audit-of-audit reads
 * remain hidden — see architecture log full-parity-mcp-2026-05-10.md §3.
 */
final class MyronListDefinitionsAction implements MyronAction
{
    public function __construct(private readonly MyronDefinitionsActionService $service) {}

    public function metadata(): MyronActionMetadata
    {
        return new MyronActionMetadata(
            uri: '/api/v1/design/definitions', method: 'GET',
            domain: 'design', resource: 'definition', verb: 'list',
            inputSchema: ['type' => 'object', 'properties' => []],
            outputSchema: ['type' => 'object', 'properties' => ['definitions' => ['type' => 'array'], 'archetypes' => ['type' => 'array']]],
            requiredScope: MyronApiScopes::DESIGN_READ,
            summary: 'List stored design definitions and packaged archetypes available to apply on this install. Each entry includes id, name, description, and kind ("packaged" archetype or operator-"stored" definition).',
            audienceClass: 2,
            snapshotInclude: false,
            exposeToMcp: true,
        );
    }

    public function execute(array $input, MyronActionCallerContext $caller): MyronActionResult
    {
        // Defensive: enumerate via the registry the service holds (private), so we
        // reuse the same DesignSystemRegistry instance the mutating actions use.
        // Cleanest: have the service expose enumeration. Inline-safe fallback: re-instantiate.
        // DesignSystemRegistry is loaded by bootstrap's app-local JSONM runtime.
        $registry = new \DesignSystemRegistry();
        if (method_exists($registry, 'ensureStorage')) $registry->ensureStorage();
        $defs = method_exists($registry, 'listDefinitions') ? (array) $registry->listDefinitions() : [];
        $archetypes = method_exists($registry, 'listPackagedArchetypes') ? (array) $registry->listPackagedArchetypes() : [];

        // APO-205-011 Fix A — packaged archetypes are immutable JSONM files; the
        // "currently active" marker lives only in current-definition.json. Stamp
        // appliedAt on the matching archetype (and any stored definition) so the
        // list response carries reciprocal telemetry: a single read answers
        // "which one is active and when was it last applied?".
        $currentId = '';
        $currentAppliedAt = null;
        if (method_exists($registry, 'currentDefinition')) {
            try {
                $current = (array) $registry->currentDefinition();
                $currentId = (string) ($current['id'] ?? '');
                $currentAppliedAt = $current['appliedAt'] ?? null;
            } catch (Throwable) {
                // non-fatal — list still returns; just no enrichment
            }
        }
        if ($currentId !== '' && $currentAppliedAt !== null) {
            foreach ($archetypes as $i => $row) {
                if (is_array($row) && (string) ($row['id'] ?? '') === $currentId) {
                    $archetypes[$i]['appliedAt'] = $currentAppliedAt;
                }
            }
            foreach ($defs as $i => $row) {
                if (is_array($row) && (string) ($row['id'] ?? '') === $currentId) {
                    $defs[$i]['appliedAt'] = $currentAppliedAt;
                }
            }
        }

        return MyronActionResult::ok([
            'definitions' => $defs,
            'archetypes' => $archetypes,
            // Convenience field for AI clients: cuts out a second resources/read.
            'currentDefinitionId' => $currentId,
        ]);
    }
}
