<?php

namespace Tests\Unit\Services\Geolocation;

use App\Services\Geolocation\ClientIpExtractor;
use Illuminate\Http\Request;
use Tests\TestCase;

class ClientIpExtractorTest extends TestCase
{
    private ClientIpExtractor $extractor;

    #[\Override]
    protected function setUp(): void
    {
        parent::setUp();
        $this->extractor = new ClientIpExtractor();
    }

    public function testReturnsFirstPublicIpFromForwardedForHeader(): void
    {
        $request = Request::create('/foo', 'GET');
        $request->headers->set('x-forwarded-for', '89.107.62.116, 172.31.23.149');

        $this->assertSame('89.107.62.116', $this->extractor->fromRequest($request));
    }

    public function testSkipsLeadingPrivateAddresses(): void
    {
        $request = Request::create('/foo', 'GET');
        $request->headers->set('x-forwarded-for', '10.0.0.1, 192.168.0.1, 203.0.113.7');

        $this->assertSame('203.0.113.7', $this->extractor->fromRequest($request));
    }

    public function testReturnsNullWhenForwardedForOnlyContainsPrivateIpsAndRemoteIsPrivate(): void
    {
        $request = Request::create('/foo', 'GET', server: ['REMOTE_ADDR' => '127.0.0.1']);
        $request->headers->set('x-forwarded-for', '10.0.0.1, 172.16.0.5');

        $this->assertNull($this->extractor->fromRequest($request));
    }

    public function testFallsBackToRequestIpWhenHeaderAbsent(): void
    {
        $request = Request::create('/foo', 'GET', server: ['REMOTE_ADDR' => '8.8.8.8']);

        $this->assertSame('8.8.8.8', $this->extractor->fromRequest($request));
    }

    public function testRejectsMalformedAddresses(): void
    {
        $request = Request::create('/foo', 'GET');
        $request->headers->set('x-forwarded-for', 'not-an-ip, also-bad');

        $this->assertNull($this->extractor->fromRequest($request));
    }
}
