<?php

declare(strict_types=1);

namespace Tests\Support\Imitation;

use App\Jobs\RouteSupplierLeadJob;
use App\Models\SupplierLead;

/**
 * Инъектор синтетических заявок для имитационного стенда (Phase 1).
 *
 * Создаёт SupplierLead в БД и синхронно прогоняет RouteSupplierLeadJob —
 * без HTTP-слоя, минуя secret/IP/rate-limit SupplierWebhookController.
 *
 * raw_payload формируется с теми же ключами (vid/project/phone/time/tag),
 * что контроллер кладёт из $request->validate(). platform парсится по тому же
 * правилу: B[123]_ → B1/B2/B3, иначе DIRECT.
 *
 * Используется исключительно в тест-инфраструктуре (Tests-namespace).
 *
 * Task 2 — Phase 1 Portal Client Imitation Harness.
 * Spec: docs/superpowers/specs/2026-06-03-portal-client-imitation-phase1-design.md
 */
final class LeadInjector
{
    /**
     * Инъектировать заявку с сигналом «сайт».
     *
     * @param  string  $domain  Домен сигнала (например, 'vashinvestor.ru').
     *                          Составляет identifier в project-поле: "{$platform}_{$domain}".
     * @param  string  $phone  Телефон в формате 7XXXXXXXXXX.
     * @param  string|null  $tag  Тег региона (например, 'Москва'); может быть null.
     * @param  string  $platform  Префикс платформы: 'B1', 'B2', 'B3' или иное (→ DIRECT).
     * @param  int|null  $vid  Внешний ID заявки поставщика. Если null — генерируется уникальный.
     */
    public function site(
        string $domain,
        string $phone,
        ?string $tag = null,
        string $platform = 'B1',
        ?int $vid = null,
    ): SupplierLead {
        $project = "{$platform}_{$domain}";

        return $this->inject($project, $phone, $tag, $platform, $vid);
    }

    /**
     * Инъектировать заявку с сигналом «звонок».
     *
     * @param  string  $number  Номер телефона для call-сигнала (7XXXXXXXXXX).
     *                          Составляет identifier в project-поле: "{$platform}_{$number}".
     * @param  string  $phone  Телефон звонящего в формате 7XXXXXXXXXX.
     * @param  string|null  $tag  Тег региона; может быть null.
     * @param  string  $platform  Префикс платформы: 'B1', 'B2', 'B3' или иное (→ DIRECT).
     * @param  int|null  $vid  Внешний ID заявки поставщика. Если null — генерируется уникальный.
     */
    public function call(
        string $number,
        string $phone,
        ?string $tag = null,
        string $platform = 'B1',
        ?int $vid = null,
    ): SupplierLead {
        $project = "{$platform}_{$number}";

        return $this->inject($project, $phone, $tag, $platform, $vid);
    }

    /**
     * Общий внутренний метод создания SupplierLead + синхронный dispatch Job.
     *
     * raw_payload содержит ровно те ключи, что SupplierWebhookController кладёт
     * из $request->validate(): vid, project, phone, time, tag (null → не добавляем,
     * чтобы не нарушить nullable-контракт RouteSupplierLeadJob).
     *
     * platform парсится по тому же правилу, что Controller::parsePlatform():
     *   /^(B[123])_/ → B1/B2/B3, иначе DIRECT.
     */
    private function inject(
        string $project,
        string $phone,
        ?string $tag,
        string $platform,
        ?int $vid,
    ): SupplierLead {
        $resolvedVid = $vid ?? $this->generateVid();
        $parsedPlatform = $this->parsePlatform($project);

        $rawPayload = [
            'vid' => $resolvedVid,
            'project' => $project,
            'phone' => $phone,
            'time' => time(),
        ];
        if ($tag !== null) {
            $rawPayload['tag'] = $tag;
        }

        $lead = SupplierLead::create([
            'platform' => $parsedPlatform,
            'raw_payload' => $rawPayload,
            'vid' => $resolvedVid,
            'phone' => $phone,
            'received_at' => now(),
            'source' => 'webhook',
        ]);

        RouteSupplierLeadJob::dispatchSync($lead->id);

        return $lead->refresh();
    }

    /**
     * Парсит platform из project-поля — идентично Controller::parsePlatform().
     * B[123]_ → B1/B2/B3, иначе DIRECT.
     */
    private function parsePlatform(string $project): string
    {
        if (preg_match('/^(B[123])_/', $project, $m) === 1) {
            return $m[1];
        }

        return 'DIRECT';
    }

    /**
     * Генерирует уникальный vid для использования, когда явный vid не передан.
     * Диапазон 1_000_000_000..9_999_999_999 — вне реальных vid поставщика (< 10^9).
     */
    private function generateVid(): int
    {
        return random_int(1_000_000_000, 9_999_999_999);
    }
}
