<?php

namespace App\Handlers;

use GuzzleHttp\Exception\GuzzleException;
use Mockery\Exception;
use Openguru\OpenCartFramework\Cache\CacheInterface;
use Openguru\OpenCartFramework\Container\Container;
use Symfony\Component\HttpFoundation\JsonResponse;
use Openguru\OpenCartFramework\Http\Request;
use Psr\Log\LoggerInterface;
use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\Telegram\Contracts\TelegramCommandInterface;
use Openguru\OpenCartFramework\Telegram\Exceptions\TelegramCommandNotFoundException;
use Openguru\OpenCartFramework\Telegram\TelegramBotStateManager;
use Openguru\OpenCartFramework\Telegram\TelegramCommandsRegistry;
use Openguru\OpenCartFramework\Telegram\TelegramService;

class TelegramHandler
{
    private CacheInterface $cache;
    private TelegramCommandsRegistry $telegramCommandsRegistry;
    private Container $container;
    private TelegramBotStateManager $telegramBotStateManager;
    private LoggerInterface $logger;
    private TelegramService $telegramService;

    public function __construct(
        CacheInterface $cache,
        TelegramCommandsRegistry $telegramCommandsRegistry,
        Container $container,
        TelegramBotStateManager $telegramBotStateManager,
        LoggerInterface $logger,
        TelegramService $telegramService
    ) {
        $this->cache = $cache;
        $this->telegramCommandsRegistry = $telegramCommandsRegistry;
        $this->container = $container;
        $this->telegramBotStateManager = $telegramBotStateManager;
        $this->logger = $logger;
        $this->telegramService = $telegramService;
    }

    /**
     * @throws GuzzleException
     * @throws \JsonException
     */
    public function webhook(Request $request): JsonResponse
    {
        $this->logger->debug('Webhook received');

        $update = $request->json();
        $message = $update['message'] ?? null;
        if (! $message) {
            return new JsonResponse([]);
        }

        $userId = $update['message']['from']['id'];
        $chatId = $update['message']['chat']['id'];

        try {
            $message = Arr::get($update, 'message', []);

            $this->cache->set('tg_latest_msg', $message, 60);

            $text = Arr::get($message, 'text', '');

            // command starts from "/"
            if (strpos($text, '/') === 0) {
                $this->telegramBotStateManager->clearState($userId, $chatId);
                $command = substr($text, 1);
                $handler = $this->telegramCommandsRegistry->resolve($command);

                /** @var TelegramCommandInterface $concrete */
                $concrete = $this->container->get($handler);
                $concrete->handle($update);

                return new JsonResponse([]);
            }

            // Continue state
            $hasState = $this->telegramBotStateManager->hasState($userId, $chatId);
            if ($hasState) {
                $handler = $this->telegramBotStateManager->getCurrentStateCommandHandler($userId, $chatId);
                /** @var TelegramCommandInterface $concrete */
                $concrete = $this->container->get($handler);
                $concrete->handle($update);

                return new JsonResponse([]);
            }
        } catch (TelegramCommandNotFoundException $exception) {
            $this->telegramService->sendMessage($chatId, 'Неверная команда');
        } catch (Exception $exception) {
            $this->logger->error($exception->getMessage(), ['exception' => $exception]);
        }

        return new JsonResponse([]);
    }
}
