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

use Doctrine\DBAL\Connection;

class MultiRowSQL implements PersistenceInterface {

    const DEFAULT_EMPTY_CONTENT = '##ZHU_LOG_EMPTY_CONTENT##';

    /** @var Connection */
    protected $connection;
    /** @var string */
    protected $dateFormat;
    /** @var string */
    protected $requestId;
    /** @var string */
    protected $method;
    /** @var string */
    protected $route;
    /** @var string */
    protected $requestType;
    /** @var string */
    protected $userId;
    /** @var string */
    protected $organizationId;
    /** @var string */
    protected $productId;
    /** @var string */
    protected $containerName;
    /** @var string */
    protected $widgetName;

    public function __construct(Connection $connection, $dateFormat = 'Y-m-d H:i:s') {
        $this->connection = $connection;
        $this->dateFormat = $dateFormat;
    }

    /**
     * {@inheritdoc}
     */
    public function logRequest(
        string $method,
        string $route,
        $requestType,
        string $content,
        string $userId,
        string $organizationId,
        $productId,
        $containerName,
        $widgetName
    ) {
        $this->requestId        = uniqid();
        $this->method           = $method;
        $this->route            = $route;
        $this->requestType      = $requestType;
        $this->userId           = $userId;
        $this->organizationId   = $organizationId;
        $this->productId        = $productId;
        $this->containerName    = $containerName;
        $this->widgetName       = $widgetName;
        $content = strlen($content) === 0 ? self::DEFAULT_EMPTY_CONTENT : $content;

        $params = [
            'TYPE'               => 'REQUEST',
            'REQ_ID'             => $this->requestId,
            'METHOD'             => $this->method,
            'ROUTE'              => $this->route,
            'REQUEST_TYPE'       => $this->requestType,
            'TIMESTAMP'          => $this->getDateTimeString(),
            'USER_ID'            => $this->userId,
            'ORGANIZATION_ID'    => $this->organizationId,
            'PRODUCT_ID'         => $this->productId,
            'CONTAINER_NAME'     => $this->containerName,
            'WIDGET_NAME'        => $this->widgetName,
            'CONTENT'            => $content,
        ];

        $this->connection->executeUpdate(
            '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)',
            $params
        );
    }

    /**
     * {@inheritdoc}
     */
    public function logResponse(int $httpResponseCode, string $content) {
        if ($this->requestId === null) {
            throw Exception::requestNotLogged();
        }

        $params = [
            'TYPE'               => 'RESPONSE',
            'HTTP_RESPONSE_CODE' => $httpResponseCode,
            'REQ_ID'             => $this->requestId,
            'METHOD'             => $this->method,
            'ROUTE'              => $this->route,
            'REQUEST_TYPE'       => $this->requestType,
            'TIMESTAMP'          => $this->getDateTimeString(),
            'USER_ID'            => $this->userId,
            'ORGANIZATION_ID'    => $this->organizationId,
            'PRODUCT_ID'         => $this->productId,
            'CONTAINER_NAME'     => $this->containerName,
            'WIDGET_NAME'        => $this->widgetName,
            'CONTENT'            => $content,
        ];

        $this->connection->executeUpdate(
            '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)',
            $params
        );
    }

    /**
     * {@inheritDoc} 
     */
    public function logException(
        string $method,
        string $route,
        $requestType,
        $content,
        $userId,
        $organizationId,
        $productId,
        $containerName,
        $widgetName
    ){
        $params = [
            'TYPE'               => 'EXCEPTION',
            'HTTP_RESPONSE_CODE' => 500,
            'REQ_ID'             => uniqid(),
            'METHOD'             => $method,
            'ROUTE'              => $route,
            'REQUEST_TYPE'       => $requestType,
            'TIMESTAMP'          => $this->getDateTimeString(),
            'USER_ID'            => $userId,
            'ORGANIZATION_ID'    => $organizationId,
            'PRODUCT_ID'         => $productId,
            'CONTAINER_NAME'     => $containerName,
            'WIDGET_NAME'        => $widgetName,
            'CONTENT'            => $content,
        ];

        $this->connection->executeUpdate(
            '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)',
            $params
        );
    }

    /**
     * @return string
     */
    protected function getDateTimeString() {
        return (new \DateTime())->format($this->dateFormat);
    }
}