<?php

namespace Comitium5\DesignerBundle\Controller;

use Comitium5\ApiClientBundle\Client\Services\BlockContentApiService;
use Comitium5\DesignerBundle\Service\BlockContent\BlockContentService;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

/**
 * Class BlockContentController
 *
 * @author Carles Gómez <carles@bab-soft.com>
 * @package Comitium5\DesignerBundle\Controller
 */
class BlockContentController extends Controller
{
    private const BLOCKED_FOR_OTHER = 1;

    private const BLOCKED_FOR_ME = 2;

    private const SUCCESS_KEY = "success";

    private const DATA_KEY = "data";

    private const BLOCKED_BY_KEY = "blockedBy";

    /**
     * @param Request $request
     *
     * @return JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function blockContentAction(Request $request): JsonResponse
    {
        $response = $this->blockContent($request->get("id"), $request->get("entityClass"));

        return $this->buildResponse($response);
    }

    /**
     * @param Request $request
     *
     * @return JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function unBlockContentAction(Request $request): JsonResponse
    {
        $response = $this->unBlockContent($request->get("id"), $request->get("entityClass"));

        return $this->buildResponse($response);
    }

    /**
     * @param Request $request
     *
     * @return JsonResponse
     */
    public function isBlockedAction(Request $request): JsonResponse
    {
        $response = $this->isBlocked($request->get("id"), $request->get("entityClass"));

        return $this->buildResponse($response);
    }

    /**
     * @param Request $request
     *
     * @return JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function getControlForBlockContentAction(Request $request): JsonResponse
    {
        $response = $this->getControlForBlockContent($request->get("id"), $request->get("entityClass"));

        return $this->buildResponse($response);
    }

    /**
     * @return BlockContentService
     */
    private function blockContentService(): BlockContentService
    {
        return new BlockContentService(
            new BlockContentApiService($this->get('designer.api')),
            $this->get('comitium5_common_widgets.cache.redis')
        );
    }

    /**
     * @param array $data
     * @param int $status
     * @return JsonResponse
     */
    private function buildResponse(array $data, $status = JsonResponse::HTTP_OK): JsonResponse
    {
        return JsonResponse::create($data, $status);
    }

    /**
     * @param int $pageId
     * @param string $resourceType
     *
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException|\Exception
     */
    public function blockContent(int $pageId, string $resourceType): array
    {
        $isBlocked = $this->isBlocked($pageId, $resourceType);

        if ($isBlocked[self::SUCCESS_KEY] === true) {
            return [
                self::SUCCESS_KEY => false,
                self::DATA_KEY    => $isBlocked[self::DATA_KEY],
                self::BLOCKED_BY_KEY => $isBlocked[self::BLOCKED_BY_KEY],
            ];
        }

        $blockedContent = $this
            ->blockContentService()
            ->block($this->getUser()->getId(), $pageId, $resourceType);

        if (empty($blockedContent)) {
            throw new \Exception(sprintf('Error on blocking %s content with id %s', $resourceType, $pageId));
        }

        return [
            self::SUCCESS_KEY => true,
            self::DATA_KEY    => $this->toArray($blockedContent),
        ];
    }

    /**
     * @param int $pageId
     * @param string $resourceType
     *
     * @return array
     */
    public function isBlocked(int $pageId, string $resourceType): array
    {
        $blockedContent = $this
            ->blockContentService()
            ->getRedisContent($pageId, $resourceType);

        if (empty($blockedContent)) {
            return [
                self::SUCCESS_KEY => false,
                self::DATA_KEY    => [],
            ];
        }

        if ($blockedContent['user']['id'] === $this->getUser()->getId()) {
            $this
                ->blockContentService()
                ->refresh($pageId, $resourceType);

            return [
                self::SUCCESS_KEY => true,
                self::DATA_KEY    => $this->toArray($blockedContent),
                self::BLOCKED_BY_KEY => self::BLOCKED_FOR_ME,
            ];
        }

        return [
            self::SUCCESS_KEY => true,
            self::DATA_KEY    => $this->toArray($blockedContent),
            self::BLOCKED_BY_KEY => self::BLOCKED_FOR_OTHER,
        ];
    }

    /**
     * @param array $blockContent
     *
     * @return array
     */
    public function toArray(array $blockContent): array
    {
        $blockContentUser = $blockContent['user'];

        $lockedDate = \DateTime::createFromFormat('Y-m-d H:i:s', $blockContent['lockedDate']);

        $data = [
            "entityId"    => $blockContent['entityId'],
            "entityClass" => $blockContent['entityClass'],
            "lockedDateFormat"  => $lockedDate->format('H:i d/m/Y'),
            "lockedDate"  => $this->get('time.templating.helper.time')->diff($lockedDate),
            "user" => null,
            "allowUnlockContent" => $this->getUser()->getPermissions()['allowUnlockContent'],
        ];

        if (!empty($blockContentUser)) {
            $data["user"] = [
                "id" => $blockContentUser['id'],
                "name" => $blockContentUser['name'],
                "surname" => $blockContentUser['surnames'],
                "fullName" => $blockContentUser['name'].' '.$blockContentUser['surnames'],
            ];
        }

        return $data;
    }

    /**
     * @param int $pageId
     * @param string $resourceType
     *
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function unBlockContent(int $pageId, string $resourceType): array
    {
        $blockedContent = $this
            ->blockContentService()
            ->getRedisContent($pageId, $resourceType);

        if (empty($blockedContent) || $blockedContent['user']['id'] !== $this->getUser()->getId()) {
            return [
                self::SUCCESS_KEY => false,
                self::DATA_KEY    => [],
            ];
        }

        $data =  [
            self::SUCCESS_KEY => true,
            self::DATA_KEY    => $this->toArray($blockedContent),
        ];

        $this
            ->blockContentService()
            ->unblock(
                $pageId,
                $resourceType
            );

        return $data;
    }

    /**
     * @param int $pageId
     * @param string $resourceType
     *
     * @return array|false[]
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    private function getControlForBlockContent(int $pageId, string $resourceType): array
    {
        $blockContentService = $this->blockContentService();

        $blockedContent = $blockContentService->getRedisContent($pageId, $resourceType);

        if ($blockedContent === null) {
            return [
                self::SUCCESS_KEY => false,
            ];
        }

        $blockedContent = $blockContentService->update($pageId, $resourceType, [
            'user' => $this->getUser()->getId(),
        ]);

        return [
            self::SUCCESS_KEY => true,
            self::DATA_KEY    => $this->toArray($blockedContent),
        ];
    }
}
