<?php

namespace Miruni\Merge_Syntax;

if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly
}

use Miruni\Merge_Syntax\Miruni_Merge_Action;
use Miruni\Merge_Syntax\Miruni_Merge_SyntaxOperation;

/**
 * Abstract base class for Miruni merge syntax handlers (strategy pattern).
 *
 * Subclasses should implement supports() to indicate which actions they handle,
 * and implement handle() to perform the operation and return the result.
 */
abstract class Miruni_Merge_Handler
{
    /**
     * Return true if this handler supports the given action.
     */
    abstract public function supports(Miruni_Merge_Action $action): bool;

    /**
     * Handle the operation. Implementations should return the result value for the merge token.
     *
     * @param Miruni_Merge_SyntaxOperation $operation
     * @param array<string,mixed> $context Optional context (WP objects, services, etc.)
     * @return mixed
     */
    abstract protected function handle(Miruni_Merge_SyntaxOperation $operation, array $context = []);

    /**
     * Execute the operation via this handler.
     *
     * @param Miruni_Merge_SyntaxOperation $operation
     * @param array<string,mixed> $context
     * @throws \InvalidArgumentException if the handler does not support the operation action.
     * @return string
     */
    public function execute(Miruni_Merge_SyntaxOperation $operation, array $context = []): string
    {
        if (!$this->supports($operation->get_action())) {
            throw new \InvalidArgumentException('Handler does not support action: ' . $operation->get_action()->value);
        }

        return $this->handle($operation, $context);
    }

    /**
     * Helper to get an argument value from the operation with a default.
     *
     * @param Miruni_Merge_SyntaxOperation $operation
     * @param string $key
     * @param mixed $default
     * @return mixed
     */
    public function arg(Miruni_Merge_SyntaxOperation $operation, string $key, $default = null)
    {
        $args = $operation->get_args();
        return array_key_exists($key, $args) ? $args[$key] : $default;
    }
}
