<?php

declare(strict_types=1);

namespace App\Services;

use App\Models\TelegramCustomer;
use Carbon\Carbon;
use Openguru\OpenCartFramework\Config\Settings;
use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\Support\Utils;
use RuntimeException;

class TelecartCustomerService
{
    private TelegramCustomer $telegramCustomer;
    private Settings $settings;

    public function __construct(TelegramCustomer $telegramCustomer, Settings $settings)
    {
        $this->telegramCustomer = $telegramCustomer;
        $this->settings = $settings;
    }

    /**
     * Сохранить или обновить Telegram-пользователя
     *
     * @param array $telegramUserData Данные пользователя из Telegram.WebApp.initDataUnsafe
     * @return array
     * @throws RuntimeException Если данные невалидны или не удалось сохранить
     */
    public function saveOrUpdate(array $telegramUserData): array
    {
        $telegramUserId = $this->extractTelegramUserId($telegramUserData);
        $telegramCustomerData = $this->prepareCustomerData($telegramUserData, $telegramUserId);

        $existingRecord = $this->telegramCustomer->findByTelegramUserId($telegramUserId);

        if ($existingRecord) {
            $this->telegramCustomer->updateByTelegramUserId($telegramUserId, $telegramCustomerData);
        } else {
            $this->telegramCustomer->create($telegramCustomerData);
        }

        return $this->telegramCustomer->findByTelegramUserId($telegramUserId);
    }

    /**
     * Извлечь Telegram user ID из данных
     *
     * @param array $telegramUserData Данные пользователя
     * @return int Telegram user ID
     * @throws RuntimeException Если ID отсутствует или невалиден
     */
    private function extractTelegramUserId(array $telegramUserData): int
    {
        $telegramUserId = (int)Arr::get($telegramUserData, 'id');

        if ($telegramUserId <= 0) {
            throw new RuntimeException('Telegram user ID is required and must be positive');
        }

        return $telegramUserId;
    }

    /**
     * Подготовить данные для сохранения в БД
     *
     * @param array $telegramUserData Исходные данные пользователя
     * @param int $telegramUserId Telegram user ID
     * @return array Подготовленные данные
     */
    private function prepareCustomerData(array $telegramUserData, int $telegramUserId): array
    {
        return [
            'telegram_user_id' => $telegramUserId,
            'username' => Arr::get($telegramUserData, 'username', $telegramUserId),
            'first_name' => Arr::get($telegramUserData, 'first_name'),
            'last_name' => Arr::get($telegramUserData, 'last_name'),
            'language_code' => Arr::get($telegramUserData, 'language_code'),
            'is_premium' => Utils::boolToInt(Arr::get($telegramUserData, 'is_premium', false)),
            'allows_write_to_pm' => Utils::boolToInt(Arr::get($telegramUserData, 'allows_write_to_pm', false)),
            'photo_url' => Arr::get($telegramUserData, 'photo_url'),
            'last_seen_at' => date('Y-m-d H:i:s'),
            'store_id' => $this->settings->get('store.oc_store_id', 0),
        ];
    }

    /**
     * Assign OpenCart Customer to Telegram User ID and return Telecart Customer ID if it exists.
     *
     * @param $telegramUserId
     * @param int $ocCustomerId
     * @return int|null
     */
    public function assignOcCustomer($telegramUserId, int $ocCustomerId): ?int
    {
        $customer = $this->telegramCustomer->findByTelegramUserId($telegramUserId);

        if (! $customer) {
            return null;
        }

        if ($customer['oc_customer_id'] === null) {
            $this->telegramCustomer->updateByTelegramUserId($telegramUserId, [
                'oc_customer_id' => $ocCustomerId,
                'updated_at' => Carbon::now()->toDateTimeString(),
            ]);
        }

        return (int)$customer['id'];
    }

    public function increaseOrdersCount(int $telecartCustomerId): void
    {
        $this->telegramCustomer->increase($telecartCustomerId, 'orders_count');
    }

    /**
     * Получить данные пользователя по Telegram user ID
     *
     * @param int $telegramUserId Telegram user ID
     * @return array|null Данные пользователя или null если не найдено
     */
    public function getByTelegramUserId(int $telegramUserId): ?array
    {
        return $this->telegramCustomer->findByTelegramUserId($telegramUserId);
    }
}
