<?php declare(strict_types=1);
/**
 * @package messenger
 * @author kputyr
 * @date 20.04.2026
 */

namespace IMATHUZH\Messenger\Tests\Rest;

use IMATHUZH\Messenger\Rest\RestRequest;
use PHPUnit\Framework\TestCase;

class RestRequestTest extends TestCase
{
    public function testGetters(): void
    {
        $request = new RestRequest('/abc/def/', 'POST', ['q' => '1'], (object)['b' => '2']);
        $this->assertEquals('/abc/def/', $request->getPath());
        $this->assertEquals('POST', $request->getMethod());
        $this->assertEquals(['q' => '1'], $request->getQuery());
        $this->assertEquals((object)['b' => '2'], $request->getBody());
    }

    public function testGetParamsWithoutPatterns(): void
    {
        $request = new RestRequest();
        $params = ['abc', 'def'];
        $request->injectParams($params);
        $this->assertEquals($params, $request->getParams());
    }

    public function testGetParamsWithPatterns(): void
    {
        $request = new RestRequest();
        $request->injectParams(['123', 'abc']);
        
        $params = $request->getParams('/\d+/', '/[a-z]+/');
        $this->assertEquals(['123', 'abc'], $params);
    }

    public function testGetParamsTooFewArguments(): void
    {
        $request = new RestRequest();
        $request->injectParams(['abc']);
        
        $this->expectException(\RuntimeException::class);
        $this->expectExceptionMessage("not enough arguments");
        $request->getParams('/\w+/', '/\w+/');
    }

    public function testGetParamsInvalidValue(): void
    {
        $request = new RestRequest();
        $request->injectParams(['abc', '123']);
        
        $this->expectException(\RuntimeException::class);
        $this->expectExceptionMessage("invalid value: 'abc'");
        $request->getParams('/\d+/', '/\d+/');
    }

    public function testGetQueryWithPatterns(): void
    {
        $request = new RestRequest('/', 'GET', ['id' => '123', 'name' => 'test']);
        
        $query = $request->getQuery(['id' => '/\d+/', 'name' => '/\w+/']);
        $this->assertEquals(['id' => '123', 'name' => 'test'], $query);
    }

    public function testGetQueryMissingParameter(): void
    {
        $request = new RestRequest('/', 'GET', ['id' => '123']);
        
        $this->expectException(\RuntimeException::class);
        $this->expectExceptionMessage("missing parameters: 'name'");
        $request->getQuery(['id' => '/\d+/', 'name' => '/\w+/']);
    }

    public function testGetBodyWithPatterns(): void
    {
        $request = new RestRequest('/', 'POST', null, (object)['id' => '123', 'val' => 'abc']);
        
        $body = $request->getBody(['id' => '/\d+/', 'val' => '/\w+/']);
        $this->assertEquals(['id' => '123', 'val' => 'abc'], $body);
    }

    public function testAssertMatchesSuccess(): void
    {
        $request = new RestRequest();
        $request->assertMatches('123', '/\d+/');
        $this->assertTrue(true); // Should not throw
    }

    public function testAssertMatchesFailure(): void
    {
        $request = new RestRequest();
        $this->expectException(\RuntimeException::class);
        $this->expectExceptionMessage("invalid value: 'abc'");
        $request->assertMatches('abc', '/\d+/');
    }

    public function testReject(): void
    {
        $request = new RestRequest();
        $this->expectException(\RuntimeException::class);
        $this->expectExceptionMessage("Custom rejection");
        $this->expectExceptionCode(400);
        $request->reject("Custom rejection", 400);
    }
}
