<?php

declare(strict_types=1);

namespace App\Tests\Behat;

use Behat\Behat\Context\Context;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface;

final class ApiCallContext implements Context
{
    private Response $response;
    private array $query = [];
    private ?string $body = null;

    public function __construct(
        private readonly KernelInterface $kernel
    ) {
    }

    /**
     * @When I send a request to ":path"
     */
    public function iSendARequestToPath(string $path): void
    {
        $this->iSendARequestToWithFollowingBody('GET', $path);
    }

    /**
     * @Then the response should be received
     */
    public function theResponseShouldBeReceived(): void
    {
        if ($this->response === null) {
            throw new \RuntimeException('No response received');
        }
    }

    /**
     * @Then the response status should be :code
     */
    public function theResponseStatusShouldBe(int $code): void
    {
        $this->theResponseShouldBeReceived();

        if ($this->response->getStatusCode() !== $code) {
            throw new \RuntimeException(
                strtr(
                    'The response code was %received% not %expected%', [
                        '%received%' => $this->response->getStatusCode(),
                        '%expected%' => $code
                    ]
                )
            );
        }
    }

    /**
     * @Given /^the request has the following body:$/
     */
    public function theRequestHasTheFollowingBody(PyStringNode $string)
    {
        $this->body = $string->getRaw();
    }

    /**
     * @Given /^the request has the following query:$/
     */
    public function theRequestHasTheFollowingQuery(TableNode $tableNode)
    {
        foreach ($tableNode as $row) {
            $this->query[$row['arg']] = $row['value'];
        }
    }

    /**
     * @When /^I send a (\w+) request to "([^"]*)"$/
     */
    public function iSendARequestToWithFollowingBody($method, $path)
    {
        $request = Request::create(
            $path.'?'.http_build_query($this->query),
            method: $method,
            content: $this->body
        );

        if ($this->body) {
            $request->headers->set('Content-Type', 'application/json');
        }

        $this->doRequest($request);
    }

    private function doRequest(Request $request): void
    {
        $this->response = $this->kernel->handle($request);
    }
}