<?php

namespace Shm\ShmCmd;

use Shm\Shm;
use Shm\ShmUtils\ShmInit;

class Cmd
{

    private static array $loopCommands = [];

    // Проверяет, запущена ли команда из командной строки
    public static function cli(): bool
    {
        return php_sapi_name() === 'cli';
    }


    public static function command(string $cmd, callable $handler): self
    {
        return new self($cmd, $handler);
    }

    public static function getLoopCommands(): array
    {
        return self::$loopCommands;
    }




    private $cmd;
    private $handler;


    public function __construct(string $cmd, callable $handler)
    {

        $this->cmd = $cmd;
        $this->handler = $handler;
        $_handler = $handler;
        $f3 = \Base::instance();
        $f3->route('GET /' . $this->cmd . ' [cli]', function ($f3) use ($_handler) {


            $argv = $f3->GET;


            ini_set('log_errors', 1);

            // Настройка глобального обработчика ошибок
            set_error_handler(function ($errno, $errstr, $errfile, $errline): void {
                $message = "Error [$errno]: $errstr in $errfile on line $errline";

                fwrite(STDERR, $message . PHP_EOL);
                // Отправляем ошибку как исключение в Sentry
                $exception = new \ErrorException($errstr, 0, $errno, $errfile, $errline);
                ShmInit::sendOnError($exception);
            });

            set_exception_handler(function ($exception): void {
                $message = "Uncaught exception: " . $exception->getMessage();
                $location = " in " . $exception->getFile() . " on line " . $exception->getLine();

                fwrite(STDERR, $message . $location . PHP_EOL);

                $trace = $exception->getTrace();

                fwrite(STDERR, "Stack trace:" . PHP_EOL);

                foreach ($trace as $index => $frame) {
                    $file = $frame['file'] ?? '[internal function]';
                    $line = $frame['line'] ?? '';
                    $function = $frame['function'] ?? '';
                    $class = $frame['class'] ?? '';
                    $type = $frame['type'] ?? '';

                    fwrite(STDERR, sprintf(
                        "#%d %s(%s): %s%s%s()\n",
                        $index,
                        $file,
                        $line,
                        $class,
                        $type,
                        $function
                    ));
                }

                ShmInit::sendOnError($exception);
            });

            register_shutdown_function(function (): void {
                $error = error_get_last();
                if ($error !== NULL) {
                    $message = "[SHUTDOWN] file: {$error['file']} | ln: {$error['line']} | msg: {$error['message']}";
                    fwrite(STDERR, $message . PHP_EOL);
                    // Отправляем в Sentry
                    \Sentry\captureMessage($message, \Sentry\Severity::fatal());
                }
            });

            $params = $argv;



            $callback = $_handler;

            $reflection = is_array($callback)
                ? new \ReflectionMethod($callback[0], $callback[1])
                : new \ReflectionFunction($callback);

            if ($reflection->getNumberOfParameters() > 0) {
                call_user_func($callback, $params);
            } else {
                call_user_func($callback);
            }
        });


        return $this;
    }

    public function monthly()
    {

        CmdSchedule::monthly($this->cmd);
        return $this;
    }

    public function weekly()
    {

        CmdSchedule::weekly($this->cmd);
        return $this;
    }
    public function daily()
    {

        CmdSchedule::daily($this->cmd);
        return $this;
    }
    public function hourly()
    {

        CmdSchedule::hourly($this->cmd);
        return $this;
    }
    public function everyMinute()
    {

        CmdSchedule::everyMinute($this->cmd);
        return $this;
    }
    public function everyFiveMinute()
    {

        CmdSchedule::everyFiveMinute($this->cmd);
        return $this;
    }
    public function everyTenMinutes()
    {

        CmdSchedule::everyTenMinutes($this->cmd);
        return $this;
    }
    public function everyFifteenMinutes()
    {

        CmdSchedule::everyFifteenMinutes($this->cmd);
        return $this;
    }
    public function everyThirtyMinutes()
    {

        CmdSchedule::everyThirtyMinutes($this->cmd);
        return $this;
    }

    public function dailyNoon()
    {

        CmdSchedule::dailyNoon($this->cmd);
        return $this;
    }

    public function inLoop(): self
    {
        if (!in_array($this->cmd, self::$loopCommands, true)) {
            self::$loopCommands[] = $this->cmd;
        }

        return $this;
    }
}
