<?php

declare(strict_types=1);

use App\Jobs\SyncSupplierProjectJob;
use App\Models\Project;
use App\Models\Tenant;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Queue;

uses(DatabaseTransactions::class);

beforeEach(fn () => Queue::fake());

it('creates a site project with valid payload', function () {
    $tenant = Tenant::factory()->withRequisites()->create();
    $user = User::factory()->create(['tenant_id' => $tenant->id]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'Окна СПб',
        'signal_type' => 'site',
        'signal_identifier' => 'okna-spb.ru',
        'daily_limit_target' => 50,
        'regions' => [],
        'delivery_days_mask' => 127,
    ]);

    $response->assertCreated();
    $response->assertJsonPath('data.sync_status', 'pending');
    expect(Project::where('signal_identifier', 'okna-spb.ru')->exists())->toBeTrue();
    Queue::assertPushed(SyncSupplierProjectJob::class);
});

it('rejects invalid site domain', function () {
    $tenant = Tenant::factory()->withRequisites()->create();
    $user = User::factory()->create(['tenant_id' => $tenant->id]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'X', 'signal_type' => 'site', 'signal_identifier' => 'not a domain',
        'daily_limit_target' => 50, 'regions' => [],
        'delivery_days_mask' => 127,
    ]);

    $response->assertStatus(422);
    $response->assertJsonValidationErrors(['signal_identifier']);
});

it('creates a call project with valid 11-digit phone', function () {
    $tenant = Tenant::factory()->withRequisites()->create();
    $user = User::factory()->create(['tenant_id' => $tenant->id]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'Натяжные', 'signal_type' => 'call', 'signal_identifier' => '79161234567',
        'daily_limit_target' => 30, 'regions' => [],
        'delivery_days_mask' => 127,
    ]);

    $response->assertCreated();
});

it('normalizes call phone starting with 8 to 7 (accepts)', function () {
    // StoreProjectRequest::prepareForValidation() нормализует call-телефон
    // через PhoneNormalizer (8XXXXXXXXXX → 7XXXXXXXXXX). UX-подсказка формы
    // обещает «можно вводить с 8 — приведём сами», поэтому 8-префикс валиден.
    $tenant = Tenant::factory()->withRequisites()->create();
    $user = User::factory()->create(['tenant_id' => $tenant->id]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'Колл 8-префикс', 'signal_type' => 'call', 'signal_identifier' => '89991234567',
        'daily_limit_target' => 30, 'regions' => [],
        'delivery_days_mask' => 127,
    ]);

    $response->assertCreated();
    expect(Project::where('name', 'Колл 8-префикс')->value('signal_identifier'))->toBe('79991234567');
});

it('rejects call signal_identifier that is not a valid RU phone', function () {
    // Слишком короткий номер не нормализуется (PhoneNormalizer → null) → regex ^7\d{10}$ не проходит.
    $tenant = Tenant::factory()->withRequisites()->create();
    $user = User::factory()->create(['tenant_id' => $tenant->id]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'X', 'signal_type' => 'call', 'signal_identifier' => '12345',
        'daily_limit_target' => 30, 'regions' => [],
        'delivery_days_mask' => 127,
    ]);

    $response->assertStatus(422);
    $response->assertJsonValidationErrors(['signal_identifier']);
});

it('creates sms project with senders + keyword', function () {
    $tenant = Tenant::factory()->withRequisites()->create();
    $user = User::factory()->create(['tenant_id' => $tenant->id]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'Ипотека', 'signal_type' => 'sms',
        'sms_senders' => ['TINKOFF'], 'sms_keyword' => 'ипотека',
        'daily_limit_target' => 100, 'regions' => [],
        'delivery_days_mask' => 127,
    ]);

    $response->assertCreated();
    $project = Project::where('name', 'Ипотека')->first();
    expect($project->sms_senders)->toBe(['TINKOFF']);
    expect($project->sms_keyword)->toBe('ипотека');
});

it('rejects sms project without sms_senders', function () {
    $tenant = Tenant::factory()->withRequisites()->create();
    $user = User::factory()->create(['tenant_id' => $tenant->id]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'X', 'signal_type' => 'sms',
        'daily_limit_target' => 100, 'regions' => [],
        'delivery_days_mask' => 127,
    ]);

    $response->assertStatus(422);
    $response->assertJsonValidationErrors(['sms_senders']);
});

it('does not cap the number of projects — limit is only by balance, not project count', function () {
    // Правило продукта: ограничение только по балансу/заказанным лидам, НЕ по числу проектов.
    // Даже явно заданный max_projects=1 не должен блокировать создание второго проекта.
    // Большой баланс — чтобы изолировать тест от балансового префлайта (он отдельный, 409).
    $tenant = Tenant::factory()->withRequisites()->create([
        'limits' => ['max_projects' => 1],
        'balance_rub' => '10000000.00',
    ]);
    $user = User::factory()->create(['tenant_id' => $tenant->id]);
    Project::factory()->create(['tenant_id' => $tenant->id, 'is_active' => true, 'daily_limit_target' => 1]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'second', 'signal_type' => 'site', 'signal_identifier' => 'second.ru',
        'daily_limit_target' => 1, 'regions' => [],
        'delivery_days_mask' => 127,
    ]);

    $response->assertCreated();
});

it('forces tenant_id from auth user (not from payload)', function () {
    $tenantA = Tenant::factory()->withRequisites()->create();
    $tenantB = Tenant::factory()->withRequisites()->create();
    $userA = User::factory()->create(['tenant_id' => $tenantA->id]);

    $this->actingAs($userA)->postJson('/api/projects', [
        'tenant_id' => $tenantB->id,  // попытка инъекции
        'name' => 'X', 'signal_type' => 'site', 'signal_identifier' => 'x.ru',
        'daily_limit_target' => 10, 'regions' => [],
        'delivery_days_mask' => 127,
    ]);

    $project = Project::where('signal_identifier', 'x.ru')->latest()->first();
    expect($project->tenant_id)->toBe($tenantA->id);
});

it('rejects site domain with consecutive dots', function () {
    $tenant = Tenant::factory()->withRequisites()->create();
    $user = User::factory()->create(['tenant_id' => $tenant->id]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'X', 'signal_type' => 'site', 'signal_identifier' => 'okna..spb.ru',
        'daily_limit_target' => 50, 'regions' => [],
        'delivery_days_mask' => 127,
    ]);

    $response->assertStatus(422);
    $response->assertJsonValidationErrors(['signal_identifier']);
});

// Plan 6 — subject-level regions[] support.

it('creates project with subject-level regions array', function () {
    $tenant = Tenant::factory()->withRequisites()->create();
    $user = User::factory()->create(['tenant_id' => $tenant->id]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'Regions Test Project',
        'signal_type' => 'site',
        'signal_identifier' => 'regions-test.example',
        'daily_limit_target' => 50,
        'delivery_days_mask' => 127,
        'regions' => [82, 83],  // Москва + СПб
    ]);

    $response->assertStatus(201);
    $response->assertJsonPath('data.regions', [82, 83]);
    $created = Project::where('name', 'Regions Test Project')->firstOrFail();
    expect($created->regions)->toBe([82, 83]);
});

it('dual-writes region_mask=255 + region_mode=include for backward-compat', function () {
    $tenant = Tenant::factory()->withRequisites()->create();
    $user = User::factory()->create(['tenant_id' => $tenant->id]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'Dual Write Test',
        'signal_type' => 'site',
        'signal_identifier' => 'dualwrite.example',
        'daily_limit_target' => 50,
        'delivery_days_mask' => 127,
        'regions' => [77],
    ]);

    $response->assertStatus(201);
    $created = Project::where('name', 'Dual Write Test')->firstOrFail();
    expect($created->region_mask)->toBe(255);
    expect($created->region_mode)->toBe('include');
});

it('rejects regions code out of 1..89 range with 422', function () {
    $tenant = Tenant::factory()->withRequisites()->create();
    $user = User::factory()->create(['tenant_id' => $tenant->id]);

    $response = $this->actingAs($user)->postJson('/api/projects', [
        'name' => 'Invalid Code Test',
        'signal_type' => 'site',
        'signal_identifier' => 'invalid.example',
        'daily_limit_target' => 50,
        'delivery_days_mask' => 127,
        'regions' => [90, 100],
    ]);

    $response->assertStatus(422);
    $response->assertJsonValidationErrors(['regions.0', 'regions.1']);
});
