<?php

declare(strict_types=1);

namespace App\Handlers;

use App\Services\TelecartCustomerService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Openguru\OpenCartFramework\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\TeleCartPulse\TrackingIdGenerator;
use Openguru\OpenCartFramework\Telegram\Enums\TelegramHeader;
use Openguru\OpenCartFramework\Telegram\Exceptions\DecodeTelegramInitDataException;
use Openguru\OpenCartFramework\Telegram\TelegramInitDataDecoder;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Throwable;

class TelegramCustomerHandler
{
    private TelecartCustomerService $telegramCustomerService;
    private LoggerInterface $logger;
    private TelegramInitDataDecoder $initDataDecoder;

    public function __construct(
        TelecartCustomerService $telegramCustomerService,
        LoggerInterface $logger,
        TelegramInitDataDecoder $initDataDecoder
    ) {
        $this->telegramCustomerService = $telegramCustomerService;
        $this->logger = $logger;
        $this->initDataDecoder = $initDataDecoder;
    }

    /**
     * Сохранить или обновить Telegram-пользователя
     *
     * @param Request $request HTTP запрос с данными пользователя
     * @return JsonResponse JSON ответ с результатом операции
     */
    public function saveOrUpdate(Request $request): JsonResponse
    {
        try {
            $customer = $this->telegramCustomerService->saveOrUpdate(
                $this->extractTelegramUserData($request)
            );

            return new JsonResponse([
                'data' => [
                    'tracking_id' => Arr::get($customer, 'tracking_id'),
                    'created_at' => Arr::get($customer, 'created_at'),
                ],
            ], Response::HTTP_OK);
        } catch (Throwable $e) {
            $this->logger->error('Could not save telegram customer data', ['exception' => $e]);

            return new JsonResponse([], Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Получить данные текущего пользователя
     *
     * @param Request $request HTTP запрос
     * @return JsonResponse JSON ответ с данными пользователя
     */
    public function getCurrent(Request $request): JsonResponse
    {
        try {
            $telegramUserData = $this->extractUserDataFromInitData($request);
            $telegramUserId = (int)Arr::get($telegramUserData, 'id');

            if ($telegramUserId <= 0) {
                return new JsonResponse([
                    'data' => null,
                ], Response::HTTP_OK);
            }

            $customer = $this->telegramCustomerService->getByTelegramUserId($telegramUserId);

            if (!$customer) {
                return new JsonResponse([
                    'data' => null,
                ], Response::HTTP_OK);
            }

            return new JsonResponse([
                'data' => [
                    'created_at' => Arr::get($customer, 'created_at'),
                ],
            ], Response::HTTP_OK);
        } catch (Throwable $e) {
            $this->logger->error('Could not get current telegram customer data', ['exception' => $e]);

            return new JsonResponse([
                'data' => null,
            ], Response::HTTP_OK);
        }
    }

    /**
     * Извлечь данные Telegram пользователя из запроса
     *
     * @param Request $request HTTP запрос
     * @return array Данные пользователя
     * @throws RuntimeException|DecodeTelegramInitDataException невозможно извлечь данные пользователя из Request
     */
    private function extractTelegramUserData(Request $request): array
    {
        $telegramUserData = $request->json('user');

        if (! $telegramUserData) {
            $telegramUserData = $this->extractUserDataFromInitData($request);
        }

        return $telegramUserData;
    }

    /**
     * @throws DecodeTelegramInitDataException
     */
    private function extractUserDataFromInitData(Request $request): array
    {
        $raw = $request->header(TelegramHeader::INIT_DATA);
        if (! $raw) {
            throw new RuntimeException('No init data found in http request header');
        }

        $initData = $this->initDataDecoder->decode($raw);

        return Arr::get($initData, 'user');
    }
}
