<?php
$dotenv = new Dotenv\Dotenv(__DIR__ . '/../');
$dotenv->load();

class BaseTest extends \PHPUnit\Framework\TestCase
{
    protected $client;
    protected static $messages = [];
    public function setUp()
    {
        $this->client = new GuzzleHttp\Client(['base_uri' => getenv('TEST_BASE_URL')]);
    }

    protected function login($username, $password)
    {
        $base_uri = getenv('TEST_BASE_URL');
        $this->client = new GuzzleHttp\Client(['base_uri' => $base_uri]);
        $url = $base_uri ."auth/login";
        $response = $this->client->request("POST", $url, [
            'header'=>[
                'Content-Type'=>'application/json',
            ],
            'json'=>[
                'username'=>$username,
                'password'=>$password,
            ]
        ]);
        return \GuzzleHttp\json_decode($response->getBody(), true);
    }

    protected function doLogin()
    {
        $base_uri = getenv('TEST_BASE_URL');
        $this->client = new GuzzleHttp\Client(['base_uri' => $base_uri]);
        $url = $base_uri ."/auth/login";
        $response = $this->client->request("POST", $url, [
            'header'=>[
                'Content-Type'=>'application/json',
            ],
            'json'=>[
                'username'=>getenv("TEST_USERNAME"),
                'password'=>getenv("TEST_PASSWORD"),
            ]
         ]);
        $statusCode = $response->getStatusCode();

        $jsonResponse = json_decode($response->getBody(), true);
        return $jsonResponse;
    }

    protected function doAPIShouldGiveSuccessResponse($method, $url, $urlParams, $expectedStatusCode, $successMessage)
    {
        $response = $this->client->request($method, $url, $urlParams);
        $statusCode = $response->getStatusCode();
        $jsonResponse = json_decode($response->getBody(), true);
        $this->assertEquals($expectedStatusCode, $statusCode);
        $this->assertContains(
            [
                'success' => true
            ],
            $jsonResponse,
            "Error on $url"
        );
        $this->assertGreaterThan(0, $jsonResponse['data']['total_record']);
        if ($successMessage != '') {
            self::$messages = array_merge(self::$messages, [$successMessage]);
        }
        return $jsonResponse;
    }

    protected function doAPIShouldGiveSimpleSuccessResponse($method, $url, $urlParams, $expectedStatusCode, $successMessage)
    {
        $response = $this->client->request($method, $url, $urlParams);
        $statusCode = $response->getStatusCode();
        $jsonResponse = json_decode($response->getBody(), true);
        $this->assertEquals($expectedStatusCode, $statusCode);
        $this->assertContains(
            [
                'success' => true
            ],
            $jsonResponse,
            "Error on $url"
        );
        if ($successMessage != '') {
            self::$messages = array_merge(self::$messages, [$successMessage]);
        }
        return $jsonResponse;
    }

    protected function doAPIShouldGiveSimpleResponse($method, $url, $urlParams, $expectedStatusCode, $successMessage)
    {
        $response = $this->client->request($method, $url, $urlParams);
        $statusCode = $response->getStatusCode();
        $jsonResponse = json_decode($response->getBody(), true);
        $this->assertEquals($expectedStatusCode, $statusCode);
        if ($successMessage != '') {
            self::$messages = array_merge(self::$messages, [$successMessage]);
        }
        return $jsonResponse;
    }

    protected function doAPIShouldGiveNotFoundResponse($method, $url, $urlParams, $expectedStatusCode, $successMessage)
    {
        $response = $this->client->request($method, $url, $urlParams);
        $statusCode = $response->getStatusCode();
        $jsonResponse = json_decode($response->getBody(), true);
        $this->assertEquals($expectedStatusCode, $statusCode);
        $this->assertContains(
            [
                'success' => true
            ],
            $jsonResponse,
            "Error on $url"
        );
        $this->assertEquals(0, $jsonResponse['data']['total_record']);
        self::$messages = array_merge(self::$messages, [$successMessage]);
    }

    protected function doShouldGiveMustBeNumericResponse($method, $url, $urlParams, $expectedStatusCode, $expectedSubsetResponse, $successMessage)
    {
        try {
            $response = $this->client->request($method, $url, $urlParams);
            $statusCode = $response->getStatusCode();
            $jsonResponse = json_decode($response->getBody(), true);
            $this->assertEquals($expectedStatusCode, $statusCode);
            self::$messages = array_merge(self::$messages, [$successMessage]);
            return $jsonResponse;
        } catch (GuzzleHttp\Exception\ClientException $e) {
            $response = $e->getResponse();
            $statusCode = $response->getStatusCode();
            $jsonResponse = json_decode($response->getBody(), true);
            $this->assertEquals($expectedStatusCode, $statusCode);
            $this->assertArraySubset(
                $expectedSubsetResponse,
                $jsonResponse,
                "Error on $url"
            );
            self::$messages = array_merge(self::$messages, [$successMessage]);
        }
    }

    public function doAPIShouldGiveRequiredResponse($method, $url, $expectedStatusCode, $expectedSubsetResponse, $successMessage)
    {
        try {
            $response = $this->client->request($method, $url);
        } catch (GuzzleHttp\Exception\ClientException $e) {
            $response = $e->getResponse();
            $statusCode = $response->getStatusCode();
            $jsonResponse = json_decode($response->getBody(), true);
            $this->assertEquals($expectedStatusCode, $statusCode);
            $this->assertArraySubset(
                $expectedSubsetResponse,
                $jsonResponse,
                "Error on $url"
            );
            self::$messages = array_merge(self::$messages, [$successMessage]);
        }
    }

    public function doAPIShouldGiveSubsetResponse($method, $url, $expectedStatusCode, $expectedSubsetResponse, $successMessage, $urlParams = array())
    {
        try {
            $response = $this->client->request($method, $url, $urlParams);
            $statusCode = $response->getStatusCode();
            $jsonResponse = json_decode($response->getBody(), true);
            $this->assertEquals($expectedStatusCode, $statusCode);
            $this->assertContains(
                [
                    'success' => true
                ],
                $jsonResponse,
                "Error on $url"
            );
            $this->assertArraySubset(
                $expectedSubsetResponse,
                $jsonResponse,
                false,
                "Error on $url"
            );
            self::$messages = array_merge(self::$messages, [$successMessage]);
            return $jsonResponse;
        } catch (GuzzleHttp\Exception\ClientException $e) {
            $response = $e->getResponse();
            $statusCode = $response->getStatusCode();
            $jsonResponse = json_decode($response->getBody(), true);
            $this->assertEquals($expectedStatusCode, $statusCode);
            $this->assertArraySubset(
                $expectedSubsetResponse,
                $jsonResponse,
                "Error on $url"
            );
            self::$messages = array_merge(self::$messages, [$successMessage]);
            return $jsonResponse;
        }
    }

    public function doAPIListShouldSuccess($url, $urlParam = [])
    {
        return $this->doAPIShouldGiveSuccessResponse(
            'GET',
            $url,
            $urlParam,
            200,
            $url . " passed"
        );
    }

    public function doAPIShouldHaveHeaders($method, $url, $urlParams, $expectedHeaderKeyValue, $successMessage)
    {
        $response = $this->client->request($method, $url, $urlParams);
        $statusCode = $response->getStatusCode();
        $jsonResponse = json_decode($response->getBody(), true);
        $this->assertEquals(200, $statusCode);
        foreach ($expectedHeaderKeyValue as $key => $value) {
            $this->assertEquals($value, $response->getHeader($key)[0]);
        }
        self::$messages = array_merge(self::$messages, [$successMessage]);
        return $jsonResponse;
    }

    protected function doAPISimpleResponseShouldGiveSuccessResponse($method, $url, $urlParams, $expectedStatusCode, $successMessage)
    {
        $response = $this->client->request($method, $url, $urlParams);
        $statusCode = $response->getStatusCode();
        $jsonResponse = json_decode($response->getBody(), true);
        $this->assertEquals($expectedStatusCode, $statusCode);
        $this->assertContains(
            [
                'success' => true
            ],
            $jsonResponse,
            "Error on $url"
        );
        if ($successMessage != '') {
            self::$messages = array_merge(self::$messages, [$successMessage]);
        }
        return $jsonResponse;
    }

    public static function tearDownAfterClass()
    {
        echo implode("\n", self::$messages);
    }

    public function testDummy()
    {
        $this->assertTrue(true);
    }
}
