<?php
/**
 * Door 3 registration helpers for B12 component write abilities.
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks;

use LolaCoreForBricks\Handlers\ComponentWriteHandler;
use LolaCoreForBricks\Support\AbilityI18n;

/**
 * Registers component write abilities on the WordPress Abilities API.
 */
final class ComponentWriteWpRegistrar
{
    public function registerAbilities(WPAbilitiesRegistrar $registrar): void
    {
        if (!function_exists('wp_register_ability')) {
            return;
        }

        foreach (ComponentWriteAbilityMap::entries() as $actionId => $entry) {
            $registrar->registerMappedWriteAbility(
                $entry['slug'],
                AbilityI18n::label($actionId),
                AbilityI18n::description($actionId),
                $this->inputSchema($actionId),
                $this->outputSchema(),
                [$this, $this->callbackMethod($actionId)],
                $entry['destructive'],
                $entry['idempotent']
            );
        }
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    public function executeCreateComponentFromElement(array $input): array
    {
        return $this->dispatch('createComponentFromElement', $input);
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    public function executeUpdateComponentProperties(array $input): array
    {
        return $this->dispatch('updateComponentProperties', $input);
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    public function executeUpdateComponent(array $input): array
    {
        return $this->dispatch('updateComponent', $input);
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    public function executeInsertComponentInstance(array $input): array
    {
        return $this->dispatch('insertComponentInstance', $input);
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    public function executeUpdateComponentInstance(array $input): array
    {
        return $this->dispatch('updateComponentInstance', $input);
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    public function executeDetachComponentInstance(array $input): array
    {
        return $this->dispatch('detachComponentInstance', $input);
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    private function dispatch(string $method, array $input): array
    {
        return (new ComponentWriteHandler())->{$method}($input, (bool) ($input['dry_run'] ?? false));
    }

    private function callbackMethod(string $actionId): string
    {
        return match ($actionId) {
            'create_component_from_element' => 'executeCreateComponentFromElement',
            'update_component_properties'   => 'executeUpdateComponentProperties',
            'update_component'              => 'executeUpdateComponent',
            'insert_component_instance'     => 'executeInsertComponentInstance',
            'update_component_instance'     => 'executeUpdateComponentInstance',
            'detach_component_instance'     => 'executeDetachComponentInstance',
            default                         => 'executeCreateComponentFromElement',
        };
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    private function inputSchema(string $actionId): array
    {
        $dryRun    = ['dry_run' => ['type' => 'boolean']];
        $component = ['component' => ['type' => 'string']];
        $page      = [
            'post_id' => ['type' => 'integer'],
            'area'    => ['type' => 'string'],
        ];

        return match ($actionId) {
            'create_component_from_element' => array_merge($dryRun, $page, [
                'element_id' => ['type' => 'string'],
                'name'       => ['type' => 'string'],
            ]),
            'update_component_properties' => array_merge($dryRun, $component, [
                'properties' => ['type' => 'array', 'items' => ['type' => 'object']],
            ]),
            'update_component' => array_merge($dryRun, $component, [
                'name'     => ['type' => 'string'],
                'elements' => ['type' => 'array', 'items' => ['type' => 'object']],
            ]),
            'insert_component_instance' => array_merge($dryRun, $component, $page, [
                'parent_id'    => ['type' => 'string'],
                'reference_id' => ['type' => 'string'],
                'position'     => ['type' => 'string'],
                'properties'   => ['type' => 'object'],
            ]),
            'update_component_instance' => array_merge($dryRun, $page, [
                'element_id'  => ['type' => 'string'],
                'instance_id' => ['type' => 'string'],
                'properties'  => ['type' => 'object'],
            ]),
            default => array_merge($dryRun, $page, [
                'element_id'  => ['type' => 'string'],
                'instance_id' => ['type' => 'string'],
            ]),
        };
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    private function outputSchema(): array
    {
        return [
            'success'       => ['type' => 'boolean'],
            'message'       => ['type' => 'string'],
            'component_id'  => ['type' => 'string'],
            'instance_id'   => ['type' => 'string'],
            'impact'        => ['type' => 'object'],
            'nesting'       => ['type' => 'object'],
            'properties'    => ['type' => 'array'],
            'coverage'      => ['type' => 'object'],
        ];
    }
}
