<?php

declare(strict_types=1);

use App\Exceptions\Supplier\SupplierClientException;
use App\Services\Supplier\Dto\SupplierProjectDto;
use App\Services\Supplier\SupplierPortalClient;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;

/*
 * rt-project-* contract tests.
 *
 * Контракт верифицирован live 2026-05-19 (Playwright MCP recon — см. план
 * Task 1: создан LIDPOTOK_TEST_DELETE_ME на crm.bp-gr.ru, записаны сетевые
 * запросы, проект удалён). Endpoints:
 *   POST /admin/visit/rt-project-save   (JSON, конверт {status,message,result,id})
 *   POST /admin/visit/rt-project-delete (JSON, конверт {status,message,result})
 *   GET  /admin/visit/rt-projects-load?src=none
 *
 * Tests use Http::fake — отделяем контракт SupplierPortalClient от реального портала.
 */

beforeEach(function (): void {
    Cache::store('redis')->put('supplier:session', [
        'phpsessid' => 'test-session',
        'csrf' => 'test-csrf',
    ], now()->addHour());

    config(['services.supplier.portal_url' => 'https://crm.bp-gr.ru']);
});

it('saveProject POSTs to /admin/visit/rt-project-save with JSON body and parses id from envelope', function (): void {
    Http::fake([
        'crm.bp-gr.ru/admin/visit/rt-project-save' => Http::response(
            ['status' => 'OK', 'message' => '', 'result' => null, 'id' => '12721245'],
            200,
        ),
    ]);

    $dto = new SupplierProjectDto(
        platform: 'B1',
        signalType: 'site',
        uniqueKey: 'lidpotok-test.local',
        limit: 100,
        workdays: [1, 2, 3, 4, 5, 6, 7],
        regions: [],
        regionsReverse: false,
        status: 'active',
    );

    $externalId = app(SupplierPortalClient::class)->saveProject($dto);

    expect($externalId)->toBe(12721245);

    Http::assertSent(function (Request $request): bool {
        $expectsB1 = $request['srcrt'] === true && $request['srcbl'] === false && $request['srcmt'] === false;

        return $request->method() === 'POST'
            && $request->url() === 'https://crm.bp-gr.ru/admin/visit/rt-project-save'
            && $request->hasHeader('Content-Type', 'application/json')
            && $request['id'] === 0
            && $request['tag'] === '_lidpotok'
            && $request['name'] === 'lidpotok-test.local'
            && $request['content'] === 'lidpotok-test.local'
            && $request['type'] === 'hosts'
            && $expectsB1
            && $request['limit'] === 100
            && $request['workdays'] === ['1', '2', '3', '4', '5', '6', '7']
            && $request['regions_reverse'] === false
            && $request['status'] === true;
    });
});

it('saveProject maps signalType call → type:"calls" and B2 → srcbl=true (single-true)', function (): void {
    Http::fake([
        'crm.bp-gr.ru/admin/visit/rt-project-save' => Http::response(
            ['status' => 'OK', 'message' => '', 'result' => null, 'id' => '12721244'],
            200,
        ),
    ]);

    $dto = new SupplierProjectDto(
        platform: 'B2',
        signalType: 'call',
        uniqueKey: '79991112233',
        limit: 50,
        workdays: [1, 2, 3],
        regions: [77],
        regionsReverse: true,
        status: 'paused',
    );

    app(SupplierPortalClient::class)->saveProject($dto);

    Http::assertSent(function (Request $request): bool {
        return $request['type'] === 'calls'
            && $request['srcrt'] === false
            && $request['srcbl'] === true
            && $request['srcmt'] === false
            // Лидерра-код 77 (Тюменская обл., конституционный порядок) переводится
            // в код поставщика 72 (ГИБДД). См. App\Support\SupplierRegions.
            && $request['regions'] === [72]
            && $request['regions_reverse'] === true
            && $request['status'] === false;
    });
});

it('updateProject POSTs to /admin/visit/rt-project-save with id:N (same endpoint as save)', function (): void {
    Http::fake([
        'crm.bp-gr.ru/admin/visit/rt-project-save' => Http::response(
            ['status' => 'OK', 'message' => '', 'result' => null, 'id' => '12721245'],
            200,
        ),
    ]);

    $dto = new SupplierProjectDto(
        platform: 'B3',
        signalType: 'sms',
        uniqueKey: 'KEYWORD',
        limit: 25,
        workdays: [1, 5],
        regions: [],
        regionsReverse: false,
        status: 'active',
    );

    app(SupplierPortalClient::class)->updateProject(12721245, $dto);

    Http::assertSent(function (Request $request): bool {
        return $request->method() === 'POST'
            && $request->url() === 'https://crm.bp-gr.ru/admin/visit/rt-project-save'
            && $request['id'] === 12721245
            && $request['type'] === 'sms'
            && $request['srcmt'] === true;
    });
});

it('deleteProject POSTs to /admin/visit/rt-project-delete with JSON {id:"<string>"}', function (): void {
    Http::fake([
        'crm.bp-gr.ru/admin/visit/rt-project-delete' => Http::response(
            ['status' => 'OK', 'message' => '', 'result' => null],
            200,
        ),
    ]);

    app(SupplierPortalClient::class)->deleteProject(12721245);

    Http::assertSent(function (Request $request): bool {
        return $request->method() === 'POST'
            && $request->url() === 'https://crm.bp-gr.ru/admin/visit/rt-project-delete'
            && $request->hasHeader('Content-Type', 'application/json')
            && $request['id'] === '12721245';
    });
});

it('listProjects extracts projects[] from the envelope and returns raw rows', function (): void {
    // Verified live 2026-05-19: ответ — конверт {projects:[...], tags, users, ...},
    // НЕ голый массив. listProjects извлекает projects.
    Http::fake([
        'crm.bp-gr.ru/admin/visit/rt-projects-load*' => Http::response([
            'projects' => [
                ['id' => '12721245', 'tag' => '_lidpotok', 'name' => 'B3_LIDPOTOK', 'type' => 'hosts', 'content' => 'foo.com'],
            ],
            'tags' => [],
            'users' => [],
        ], 200),
    ]);

    $list = app(SupplierPortalClient::class)->listProjects();

    expect($list)->toHaveCount(1);
    expect($list[0]['id'])->toBe('12721245');
    expect($list[0]['name'])->toBe('B3_LIDPOTOK');

    Http::assertSent(function (Request $request): bool {
        return $request->method() === 'GET'
            && str_contains($request->url(), '/admin/visit/rt-projects-load')
            && $request->data() === ['src' => 'none'];
    });
});

it('listProjects returns empty array when envelope has no projects key', function (): void {
    Http::fake([
        'crm.bp-gr.ru/admin/visit/rt-projects-load*' => Http::response(['tags' => []], 200),
    ]);

    expect(app(SupplierPortalClient::class)->listProjects())->toBe([]);
});

it('saveProject throws SupplierClientException on HTTP 200 + status:"Error"', function (): void {
    Http::fake([
        'crm.bp-gr.ru/admin/visit/rt-project-save' => Http::response(
            ['status' => 'Error', 'message' => 'Лимит недостаточен!', 'result' => null],
            200,
        ),
    ]);

    $dto = new SupplierProjectDto(
        platform: 'B1',
        signalType: 'site',
        uniqueKey: 'rejected.local',
        limit: 1,
        workdays: [1, 2, 3, 4, 5, 6, 7],
        regions: [],
        regionsReverse: false,
        status: 'active',
    );

    expect(fn () => app(SupplierPortalClient::class)->saveProject($dto))
        ->toThrow(SupplierClientException::class, 'Лимит недостаточен!');
});

it('deleteProject throws SupplierClientException on HTTP 200 + status:"Error"', function (): void {
    Http::fake([
        'crm.bp-gr.ru/admin/visit/rt-project-delete' => Http::response(
            ['status' => 'Error', 'message' => 'Проект не найден', 'result' => null],
            200,
        ),
    ]);

    expect(fn () => app(SupplierPortalClient::class)->deleteProject(99999999))
        ->toThrow(SupplierClientException::class, 'Проект не найден');
});
