<?php
namespace tests\Zeedhi\ZhuLog\Logger\Persistence;

use Zeedhi\ZhuLog\Logger\Persistence\MultiRowSQL;
use Zeedhi\ZhuLog\Logger\Persistence\Exception;
use Doctrine\DBAL\Connection;

class MultiRowSQLTest extends \PHPUnit_Framework_TestCase {

    const UNIQID_REGEX = '/^\w{13}$/';
    const DATE_REGEX = '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/';

    public function setUp() {
        $this->connection = $this->getMockBuilder(Connection::class)
            ->setMethods(['executeUpdate'])
            ->disableOriginalConstructor()
            ->getMock();

        $this->persistenceStrategy = new MultiRowSQL($this->connection, 'Y-m-d H:i:s');
    }

    public function testLogRequest() {
        $this->connection->expects($this->once())->method('executeUpdate')
            ->with('INSERT INTO ZH_LOG (TYPE, REQ_ID, METHOD, ROUTE, REQUEST_TYPE, TIMESTAMP, USER_ID, ORGANIZATION_ID, PRODUCT_ID, CONTAINER_NAME, WIDGET_NAME, CONTENT) VALUES (:TYPE, :REQ_ID, :METHOD, :ROUTE, :REQUEST_TYPE, :TIMESTAMP, :USER_ID, :ORGANIZATION_ID, :PRODUCT_ID, :CONTAINER_NAME, :WIDGET_NAME, :CONTENT)',
                $this->callback(function($queryParams) {
                    $this->assertCount(12, $queryParams);
                    $this->assertArraySubset([
                        'TYPE'           => 'REQUEST',
                        'METHOD'         => 'POST',
                        'ROUTE'          => '/foo',
                        'REQUEST_TYPE'   => 'DataSet',
                        'USER_ID'        => 1,
                        'ORGANIZATION_ID'=> 1,
                        'PRODUCT_ID'     => NULL,
                        'CONTAINER_NAME' => NULL,
                        'WIDGET_NAME'    => NULL,
                        'CONTENT'        => 'Request content',
                    ], $queryParams);
                    $this->assertArrayHasKey('REQ_ID', $queryParams);
                    $this->assertRegExp(self::UNIQID_REGEX, $queryParams['REQ_ID']);
                    $this->assertArrayHasKey('TIMESTAMP', $queryParams);
                    $this->assertRegExp(self::DATE_REGEX, $queryParams['TIMESTAMP']);
                    return true;
                })
            );

        $method         = 'POST';
        $route          = '/foo';
        $requestType    = 'DataSet';
        $userId         = 1;
        $organizationId = 1;
        $productId      = null;
        $containerName  = null;
        $widgetName     = null;
        $content        = 'Request content';
        $this->persistenceStrategy->logRequest(
            $method,
            $route,
            $requestType,
            $content,
            $userId,
            $organizationId,
            $productId,
            $containerName,
            $widgetName
        );
    }

    public function testLogResponse() {
        $this->connection->expects($this->exactly(2))->method('executeUpdate');

        $this->persistenceStrategy->logRequest('POST', '/foo', 'DataSet', 'Request content', 1, 1, null, null, null);

        $this->connection->expects($this->once())
            ->method('executeUpdate')
            ->with('INSERT INTO ZH_LOG (TYPE, HTTP_RESPONSE_CODE, REQ_ID, METHOD, ROUTE, REQUEST_TYPE, TIMESTAMP, USER_ID, ORGANIZATION_ID, PRODUCT_ID, CONTAINER_NAME, WIDGET_NAME, CONTENT) VALUES (:TYPE, :HTTP_RESPONSE_CODE, :REQ_ID, :METHOD, :ROUTE, :REQUEST_TYPE, :TIMESTAMP, :USER_ID, :ORGANIZATION_ID, :PRODUCT_ID, :CONTAINER_NAME, :WIDGET_NAME, :CONTENT)',
                $this->callback(function($queryParams) {
                    $this->assertCount(13, $queryParams);
                    $this->assertArraySubset([
                        'TYPE'               => 'RESPONSE',
                        'HTTP_RESPONSE_CODE' => 200,
                        'METHOD'             => 'POST',
                        'ROUTE'              => '/foo',
                        'REQUEST_TYPE'       => 'DataSet',
                        'USER_ID'            => 1,
                        'ORGANIZATION_ID'    => 1,
                        'PRODUCT_ID'         => NULL,
                        'CONTAINER_NAME'     => NULL,
                        'WIDGET_NAME'        => NULL,
                        'CONTENT'            => 'Response content',
                    ], $queryParams);
                    $this->assertArrayHasKey('REQ_ID', $queryParams);
                    $this->assertRegExp(self::UNIQID_REGEX, $queryParams['REQ_ID']);
                    $this->assertArrayHasKey('TIMESTAMP', $queryParams);
                    $this->assertRegExp(self::DATE_REGEX, $queryParams['TIMESTAMP']);
                    return true;
                })
            );

        $httpResponseCode = 200;
        $content          = 'Response content';
        $this->persistenceStrategy->logResponse($httpResponseCode, $content);
    }

    public function testLogResponseWithoutLoggingRequest() {
        $this->expectException(Exception::class);
        $this->expectExceptionMessage('Can\'t log response because request was not logged');

        $this->persistenceStrategy->logResponse(200, 'Response content');
    }

    public function testLogException() {
        $this->connection->expects($this->exactly(2))->method('executeUpdate');

        $this->persistenceStrategy->logRequest('POST', '/foo', 'DataSet', 'Request content', 1, 1, null, null, null);

        
        $this->connection->expects($this->once())
        ->method('executeUpdate')
        ->with('INSERT INTO ZH_LOG (TYPE, HTTP_RESPONSE_CODE, REQ_ID, METHOD, ROUTE, REQUEST_TYPE, TIMESTAMP, USER_ID, ORGANIZATION_ID, PRODUCT_ID, CONTAINER_NAME, WIDGET_NAME, CONTENT) VALUES (:TYPE, :HTTP_RESPONSE_CODE, :REQ_ID, :METHOD, :ROUTE, :REQUEST_TYPE, :TIMESTAMP, :USER_ID, :ORGANIZATION_ID, :PRODUCT_ID, :CONTAINER_NAME, :WIDGET_NAME, :CONTENT)',
            $this->callback(function($queryParams) {
                $this->assertCount(13, $queryParams);
                $this->assertArraySubset([
                    'TYPE'               => 'EXCEPTION',
                    'HTTP_RESPONSE_CODE' => 500,
                    'METHOD'             => 'POST',
                    'ROUTE'              => '/foo',
                    'REQUEST_TYPE'       => 'DataSet',
                    'USER_ID'            => 1,
                    'ORGANIZATION_ID'    => 1,
                    'PRODUCT_ID'         => NULL,
                    'CONTAINER_NAME'     => NULL,
                    'WIDGET_NAME'        => NULL,
                    'CONTENT'            => '{"message": "Generic exception"}',
                ], $queryParams);
                $this->assertArrayHasKey('REQ_ID', $queryParams);
                $this->assertRegExp(self::UNIQID_REGEX, $queryParams['REQ_ID']);
                $this->assertArrayHasKey('TIMESTAMP', $queryParams);
                $this->assertRegExp(self::DATE_REGEX, $queryParams['TIMESTAMP']);
                return true;
            })
        );
    
        $this->persistenceStrategy->logException('POST', '/foo', 'DataSet', '{"message": "Generic exception"}', 1, 1, null, null, null);
    }
}