<?php

namespace FR\V1_0\Controllers;

use FR\Interfaces\RemoteHubInterface;
use FR\V1_0\Entities\RemoteHub\CreateRemoteHubEntity;
use FR\V1_0\Entities\RemoteHub\RemoteHub;
use FR\V1_0\Entities\RemoteHub\RemoteHubsCollection;
use FR\V1_0\Models\RemoteHubModel as RemoteHubModel;
use FR\V1_0\Models\RemoteHubStatisticsModel;
use FR\V1_0\Models\SetupHubModel;

/**
 * @uri /fr/v1.0/remote-hub
 * @uri /fr/remote-hub
 */
class RemoteHubCreateList extends \CfProtectedResource
{
    private $remoteHubModel;
    private $remoteHubStatisticsModel;
    private $setupHubModel;

    public function __construct($parameters)
    {
        parent::__construct($parameters);

        $cfSettings = \CfSettings::getInstance()->getConnection();
        $cfdb = \CfdbPdo::getInstance()->getConnection();
        $this->remoteHubModel = new RemoteHubModel($cfSettings, $cfdb);
        $this->setupHubModel = new SetupHubModel($cfSettings, $this->username);
        $this->remoteHubStatisticsModel = new RemoteHubStatisticsModel($cfdb, $this->username);
    }

    /**
     * @param $request
     *
     * @rbacName Remote hubs list
     * @rbacGroup Remote hub API
     * @rbacAlias remoteHub.list
     *
     * @return \Response
     */
    public function get($request)
    {
        $includeStatistics = \Utils::queryParam('expand') == 'statistics';
        $response = new \Response($request);
        $remoteHubsCollection = new RemoteHubsCollection();
        foreach ($this->remoteHubModel->getList() as $hub) {
            if ($includeStatistics && $hub['role'] === RemoteHub::FEEDER_ROLE) {
                $hub['statistics'] = $this->remoteHubStatisticsModel->getStatistics($hub['hostkey']);
            }
            $remoteHubsCollection->addRemoteHub(CreateRemoteHubEntity::createFromDbResult($hub));
        }

        $response->body = json_encode($remoteHubsCollection->toArray());
        $response->code = \Response::OK;

        return $response;
    }

    /**
     * @param $request
     *
     * @rbacName Create remote hub
     * @rbacGroup Remote hub API
     * @rbacAlias remoteHub.create
     *
     * @return \Response
     * @throws \ResponseException
     */
    public function post($request)
    {
        $response = new \Response($request);

        $data = \Utils::getValidJsonData($request->data);

        /**
         * @var $hubEntity RemoteHubInterface
         */
        $hubEntity = CreateRemoteHubEntity::createFromStdClass($data);
        $this->validate($hubEntity);
        $values = $hubEntity->toArray();
        $values['transport'] = is_array($values['transport']) ? json_encode($values['transport']) : $values['transport'];
        $this->remoteHubModel->create($values);
        $response->code = \Response::CREATED;
        return $response;
    }

    private function validate(RemoteHub $hub)
    {
        if ($this->setupHubModel->isConfigured() !== true) {
            throw new \ResponseException('You cannot perform this action, hub is not enabled for Federated Reporting.', \Response::BADREQUEST);
        }

        if ($hub->getRole() == RemoteHub::SUPERHUB_ROLE && $this->setupHubModel->getHubRole() == RemoteHub::SUPERHUB_ROLE) {
            throw new \ResponseException('You cannot add remote superhub to existing superhub.', \Response::BADREQUEST);
        }

        if ($hub->getRole() == RemoteHub::FEEDER_ROLE && $this->setupHubModel->getHubRole() == RemoteHub::FEEDER_ROLE) {
            throw new \ResponseException('You cannot add remote feeder hub to existing feeder hub.', \Response::BADREQUEST);
        }

        if ($this->remoteHubModel->findByName($hub->getUiName())) {
            throw new \ResponseException(sprintf('Remote hub with name `%s` already exists', $hub->getUiName()), \Response::BADREQUEST);
        }
    }

}

/**
 * @uri /fr/v1.0/remote-hub/:id
 * @uri /fr/remote-hub/:id
 */
class RemoteHubPutDeleteView extends \CfProtectedResource
{
    private $remoteHubModel;

    public function __construct($parameters)
    {
        parent::__construct($parameters);

        $this->remoteHubModel = new RemoteHubModel(\CfSettings::getInstance()->getConnection(), \CfdbPdo::getInstance()->getConnection());
    }

    /**
     * @param $request
     * @param $id
     *
     * @rbacName Get remote hub
     * @rbacGroup Remote hub API
     * @rbacAlias remoteHub.get
     *
     * @return \Response
     */
    public function get($request, $id)
    {
        $response = new \Response($request);

        $hubEntity = CreateRemoteHubEntity::createFromDbResult($this->remoteHubModel->get($id));
        $response->body = json_encode($hubEntity->toArray());
        $response->code = \Response::OK;

        return $response;
    }

    /**
     * @param $request
     * @param $id
     *
     * @rbacName Update remote hub
     * @rbacGroup Remote hub API
     * @rbacAlias remoteHub.update
     *
     * @return \Response
     * @throws \ResponseException
     */
    public function put($request, $id)
    {
        $response = new \Response($request);
        $data = \Utils::getValidJsonData($request->data);

        // check if remote hub exists
        $this->remoteHubModel->get($id);
        /**
         * @var $hubEntity RemoteHubInterface
         */
        $hubEntity = CreateRemoteHubEntity::createFromStdClass($data);

        $values = $hubEntity->toArray();
        $values['transport'] = is_array($values['transport']) ? json_encode($values['transport']) : $values['transport'];

        $this->remoteHubModel->update($id, $values);
        $response->code = \Response::ACCEPTED;

        return $response;
    }

    /**
     * @param $request
     * @param $id
     *
     * @rbacName Delete remote hub
     * @rbacGroup Remote hub API
     * @rbacAlias remoteHub.delete
     *
     * @return \Response
     */
    public function delete($request, $id)
    {
        $response = new \Response($request);

        // check if remote hub exists
        $this->remoteHubModel->get($id);
        $this->remoteHubModel->delete($id);
        $response->code = \Response::ACCEPTED;

        return $response;
    }
}
