<?php

declare(strict_types=1);

namespace Plugin\tnt_mcp\src\Mcp\Tools;

use Closure;
use Plugin\tnt_mcp\src\Mcp\Commerce\PaymentMethodReader;
use Plugin\tnt_mcp\src\Mcp\Contracts\Tool;
use Plugin\tnt_mcp\src\Mcp\Mode\EndpointClass;
use RuntimeException;

/**
 * READ tool: one payment method as the whole domain object — its module settings with their
 * declared keys and allowed values, per-language texts, customer-group restriction, the decoded
 * mail bitmask, and the shipping methods that offer it with their surcharges.
 *
 * This is the read that `payment.method.saveConfig` needs first: that endpoint rewrites the mail
 * bitmask, every language row and the whole module settings block from what it is sent, so
 * anything not read back here and returned is cleared.
 */
final class GetPaymentMethod implements Tool
{
    /** @param Closure(): PaymentMethodReader $readerFactory must not touch the DB until run() */
    public function __construct(private readonly Closure $readerFactory)
    {
    }

    public function name(): string
    {
        return 'get_payment_method';
    }

    public function description(): string
    {
        return 'Get one payment method in full: module settings, languages, customer groups, mail '
            . 'flags and the shipping methods offering it.';
    }

    /** @return array<string,mixed> */
    public function inputSchema(): array
    {
        return [
            'type'       => 'object',
            'properties' => [
                'paymentMethodId' => [
                    'type'        => 'integer',
                    'minimum'     => 1,
                    'description' => 'Internal id (tzahlungsart.kZahlungsart). Pass this or name.',
                ],
                'name'            => [
                    'type'        => 'string',
                    'description' => 'Exact payment method name (tzahlungsart.cName) or its module '
                        . 'id (cModulId, e.g. "za_rechnung_jtl").',
                ],
            ],
            'additionalProperties' => false,
        ];
    }

    public function isWrite(): bool
    {
        return false;
    }

    public function scope(): string
    {
        return 'shop:read';
    }

    public function endpointClass(): EndpointClass
    {
        return EndpointClass::Reversible;
    }

    /**
     * @param array<string,mixed> $args
     * @return array<string,mixed>
     */
    public function run(array $args): array
    {
        $id   = $args['paymentMethodId'] ?? null;
        $name = $args['name'] ?? null;
        if ($id !== null && (!\is_int($id) || $id < 1)) {
            throw new RuntimeException(
                'get_payment_method: "paymentMethodId" must be a positive whole number.'
            );
        }
        if ($name !== null && !\is_string($name)) {
            throw new RuntimeException('get_payment_method: "name" must be a string.');
        }
        $name = \is_string($name) ? \trim($name) : null;
        if ($id === null && ($name === null || $name === '')) {
            throw new RuntimeException(
                'get_payment_method: pass either "paymentMethodId" or "name".'
            );
        }

        $method = ($this->readerFactory)()->method($id ?? (string)$name);
        if ($method === null) {
            return [
                'found'  => false,
                'reason' => $id !== null
                    ? 'No payment method has id ' . $id . '.'
                    : 'No payment method is named "' . $name . '" and none uses it as a module id. '
                        . 'Call list_payment_methods for the exact spelling.',
            ];
        }

        return ['found' => true] + $method;
    }
}
