<?php

namespace Tests\Tenant\ImportMapSources;

use App\Models\ImportMap;
use App\Models\ImportMapField;
use App\Modules\Stock\ImportMapSources\HttpJsonSource;
use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Facades\Http;
use Tests\TenantTestCase;

class HttpJsonSourceTest extends TenantTestCase
{
    public function testNameIsStable(): void
    {
        $this->assertEquals('http_json', (new HttpJsonSource())->name());
    }

    public function testFetchYieldsRowsFromConfiguredArrayPath(): void
    {
        Http::fake([
            'example.test/feed' => Http::response([
                'checks' => [
                    ['vin' => 'A1', 'soh' => 95],
                    ['vin' => 'A2', 'soh' => 87],
                ],
            ]),
        ]);

        $map = ImportMap::factory()->create([
            'data' => [
                'source_type' => 'http_json',
                'http' => [
                    'url' => 'https://example.test/feed',
                    'array_path' => 'checks',
                ],
            ],
        ]);

        $rows = iterator_to_array((new HttpJsonSource())->fetch($map));

        $this->assertCount(2, $rows);
        $this->assertEquals('A1', $rows[0]['vin']);
        $this->assertEquals(87, $rows[1]['soh']);
    }

    public function testFetchYieldsRootWhenArrayPathOmitted(): void
    {
        Http::fake([
            'example.test/list' => Http::response([
                ['vin' => 'A1'],
                ['vin' => 'A2'],
            ]),
        ]);

        $map = ImportMap::factory()->create([
            'data' => [
                'source_type' => 'http_json',
                'http' => ['url' => 'https://example.test/list'],
            ],
        ]);

        $rows = iterator_to_array((new HttpJsonSource())->fetch($map));

        $this->assertCount(2, $rows);
    }

    public function testFetchSendsConfiguredHeaders(): void
    {
        Http::fake([
            'example.test/*' => Http::response(['rows' => []]),
        ]);

        $map = ImportMap::factory()->create([
            'data' => [
                'source_type' => 'http_json',
                'http' => [
                    'url' => 'https://example.test/feed',
                    'headers' => [
                        ['key' => 'x-api-key', 'value' => 'secret-token'],
                    ],
                    'array_path' => 'rows',
                ],
            ],
        ]);

        iterator_to_array((new HttpJsonSource())->fetch($map));

        Http::assertSent(fn ($request) => $request->hasHeader('x-api-key', 'secret-token'));
    }

    public function testKeepLatestPerMatchKeyGroupsByMatchFields(): void
    {
        Http::fake([
            'example.test/health' => Http::response([
                'checks' => [
                    ['vin' => 'VIN1', 'soh' => 90, 'test_date' => '2026-01-10'],
                    ['vin' => 'VIN1', 'soh' => 85, 'test_date' => '2026-03-15'],
                    ['vin' => 'VIN2', 'soh' => 70, 'test_date' => '2026-02-01'],
                ],
            ]),
        ]);

        $map = ImportMap::factory()->create([
            'data' => [
                'source_type' => 'http_json',
                'http' => [
                    'url' => 'https://example.test/health',
                    'array_path' => 'checks',
                    'latest_by' => 'test_date',
                ],
            ],
        ]);
        ImportMapField::create([
            'map_id' => $map->id,
            'on_file' => 'vin',
            'on_model' => 'vin',
            'is_match_key' => true,
        ]);
        $map->load('fields');

        $rows = iterator_to_array((new HttpJsonSource())->fetch($map));

        // VIN1 should have the 2026-03-15 (soh 85), VIN2 unchanged
        $this->assertCount(2, $rows);
        $byVin = collect($rows)->keyBy('vin');
        $this->assertEquals(85, $byVin['VIN1']['soh']);
        $this->assertEquals(70, $byVin['VIN2']['soh']);
    }

    public function testKeepLatestSkippedWhenNoMatchFieldsFlagged(): void
    {
        Http::fake([
            'example.test/health' => Http::response([
                'checks' => [
                    ['vin' => 'VIN1', 'soh' => 90, 'test_date' => '2026-01-10'],
                    ['vin' => 'VIN1', 'soh' => 85, 'test_date' => '2026-03-15'],
                ],
            ]),
        ]);

        $map = ImportMap::factory()->create([
            'data' => [
                'source_type' => 'http_json',
                'http' => [
                    'url' => 'https://example.test/health',
                    'array_path' => 'checks',
                    'latest_by' => 'test_date',
                ],
            ],
        ]);
        // no is_match_key fields → no dedupe possible, all rows pass through
        $map->load('fields');

        $rows = iterator_to_array((new HttpJsonSource())->fetch($map));

        $this->assertCount(2, $rows);
    }

    public function testThrowsWhenUrlMissing(): void
    {
        $map = ImportMap::factory()->create([
            'data' => ['source_type' => 'http_json', 'http' => []],
        ]);

        $this->expectException(\InvalidArgumentException::class);
        iterator_to_array((new HttpJsonSource())->fetch($map));
    }

    public function testThrowsOnHttpErrorResponse(): void
    {
        Http::fake([
            'example.test/*' => Http::response('boom', 500),
        ]);

        $map = ImportMap::factory()->create([
            'data' => [
                'source_type' => 'http_json',
                'http' => ['url' => 'https://example.test/feed'],
            ],
        ]);

        $this->expectException(RequestException::class);
        iterator_to_array((new HttpJsonSource())->fetch($map));
    }

    public function testInvalidArrayPathYieldsNothing(): void
    {
        Http::fake([
            'example.test/*' => Http::response(['foo' => 'bar']),
        ]);

        $map = ImportMap::factory()->create([
            'data' => [
                'source_type' => 'http_json',
                'http' => [
                    'url' => 'https://example.test/feed',
                    'array_path' => 'does.not.exist',
                ],
            ],
        ]);

        $rows = iterator_to_array((new HttpJsonSource())->fetch($map));

        $this->assertEmpty($rows);
    }
}
