<?php
namespace EasyChat\Library\AiProvider;















class ToolExecutor {

     
    private $handlers = [];

    



    private $logger = null;

    





    public function register($name, callable $handler) {
        $this->handlers[(string)$name] = $handler;
        return $this;
    }

    





    public function setLogger($logger) {
        $this->logger = is_callable($logger) ? $logger : null;
        return $this;
    }

    public function has($name) {
        return isset($this->handlers[(string)$name]);
    }

    





    public function execute($name, array $args) {
        $name = (string)$name;

        if (!isset($this->handlers[$name])) {
            $this->logLine("[ToolExecutor] Неизвестный инструмент: \"{$name}\"");
            return ['error' => "Unknown tool: $name"];
        }

         
         
        $this->logLine("[ToolExecutor] LLM вызвал инструмент: \"{$name}\" | Аргументы: " . $this->summarizeArguments($args));

        try {
            $result = call_user_func($this->handlers[$name], $args);

             
            $this->logLine("[ToolExecutor] Результат \"{$name}\": " . $this->summarize($result));

            return $result;
        } catch (\Throwable $e) {
            $this->logLine("[ToolExecutor] Ошибка \"{$name}\": " . $e->getMessage());
            return ['error' => $e->getMessage()];
        }
    }

    public function getNames() {
        return array_keys($this->handlers);
    }

     
     
     

    


    private function logLine(string $message): void {
        if ($this->logger !== null) {
            call_user_func($this->logger, $message);
        }
    }

    



    private function summarize($result): string {
        if (!is_array($result)) {
            return json_encode($result, JSON_UNESCAPED_UNICODE);
        }

        if (isset($result['error'])) {
            return 'error: ' . $result['error'];
        }

        $parts = [];
        foreach (['products', 'pages'] as $key) {
            if (isset($result[$key]) && is_array($result[$key])) {
                $parts[] = count($result[$key]) . ' ' . $key;
            }
        }

        if (!empty($parts)) {
            return 'найдено: ' . implode(', ', $parts);
        }

         
        $raw = json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        return ($this->textLength($raw) > 300) ? $this->textSlice($raw, 300) . '…' : $raw;
    }

    


    private function summarizeArguments(array $args): string {
        if (empty($args)) {
            return 'нет';
        }

        $parts = array();
        foreach ($args as $key => $value) {
            $key = preg_replace('/[^A-Za-z0-9_.-]/', '', (string)$key);
            if ($key === '') {
                $key = 'field';
            }
            if (is_string($value)) {
                $parts[] = $key . '=string(' . $this->textLength($value) . ')';
            } elseif (is_array($value)) {
                $parts[] = $key . '=array(' . count($value) . ')';
            } elseif (is_bool($value)) {
                $parts[] = $key . '=boolean';
            } elseif (is_int($value)) {
                $parts[] = $key . '=integer';
            } elseif (is_float($value)) {
                $parts[] = $key . '=number';
            } elseif ($value === null) {
                $parts[] = $key . '=null';
            } else {
                $parts[] = $key . '=' . gettype($value);
            }
        }

        return implode(', ', array_slice($parts, 0, 20));
    }

    private function textLength(string $value): int {
        return function_exists('mb_strlen')
            ? (int)\mb_strlen($value, 'UTF-8')
            : strlen($value);
    }

    private function textSlice(string $value, int $length): string {
        return function_exists('mb_substr')
            ? (string)\mb_substr($value, 0, $length, 'UTF-8')
            : substr($value, 0, $length);
    }
}
