<?php

use CMDB\CMDBResource;
use CMDB\CMDBSpecificItem;

trait SharedGroupVerification
{
    public function isSharedGroupExists(int $id): bool
    {
        return boolval($this->sharedHostGroupsModel->get(intval($id)));
    }
}

/**
 * @uri /host-groups/shared/:id/cmdb 0
 */
class SharedGroupCMDBItem extends CMDBResource
{
    use SharedGroupVerification;
    /**
     * @var CmdbItemModel
     */
    private $cmdbItemModel;
    private $sharedHostGroupsModel;

    public function __construct($parameters)
    {
        parent::__construct($parameters);
        $this->cmdbItemModel = new SharedGroupCmdbModel($this->username);

        $this->sharedHostGroupsModel = new SharedHostGroupsModel($this->username);

        if (!isActionAllowed($this->username, 'host-groups-shared.get')) {
            throw new AccessDenyException("Action is not allowed. Permission to view shared group is missing.");
        }
    }

    /**
     * @rbacName Get data
     * @rbacGroup Shared host group configuration management data
     * @rbacAlias shared-group-cmdb.get
     * @rbacAllowedByDefault
     */
    public function get($request, $groupId)
    {
        $response = new \Response($request);
        $response->code = \Response::OK;

        if (!$this->isSharedGroupExists($groupId)) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

        $value = json_encode($this->cmdbItemModel->get($groupId));
        if ($value === null) {
            $response->code = \Response::NOTFOUND;
        }
        $response->body = $value;

        return $response;
    }

    /**
     * @rbacName Create data
     * @rbacGroup Shared host group configuration management data
     * @rbacAlias shared-group-cmdb.create
     */
    public function patch($request, $groupId)
    {
        $requestData = \Utils::getValidJsonData($request->data);
        $requestData->groupId = $groupId;
        $response = new \Response($request);
        $response->code = \Response::OK;

        if (!$this->isSharedGroupExists($groupId)) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

        try {
            $newCmdbItem = SharedGroupCmdbItemEntity::fromRequest($requestData);
            $cmdbFromDB = $this->cmdbItemModel->get($groupId);

            if ($cmdbFromDB !== false && is_array($cmdbFromDB)) {
                $combinedCMDB = SharedGroupCmdbItemEntity::setOldEntityValuesFromNew($newCmdbItem, SharedGroupCmdbItemEntity::fromDB($cmdbFromDB));
                $this->cmdbItemModel->update($combinedCMDB);
            } else {
                $this->cmdbItemModel->createOrUpdate($newCmdbItem);
            }
            $this->sharedHostGroupsModel->sendCmdbRefreshPsqlNotification();
        } catch (\InvalidArgumentException $exception) {
            $response->body = $exception->getMessage();
            $response->code = \Response::BADREQUEST;
        }

        return $response;
    }

    /**
     * @param $request
     * @param $groupId
     * @return \Response
     *
     * @rbacName Delete data
     * @rbacGroup Shared host group configuration management data
     * @rbacAlias shared-group-cmdb.delete
     */
    public function delete($request, $groupId)
    {
        $response = new \Response($request);

        if (!$this->isSharedGroupExists($groupId)) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

        $response->body = $this->cmdbItemModel->delete($groupId);
        $this->sharedHostGroupsModel->sendCmdbRefreshPsqlNotification();
        $response->code = \Response::NOCONTENT;
        return $response;
    }
}

/**
 * id - group id
 * type - string, "class" or "variable"
 * name - name of the class or variable
 *
 * @uri /host-groups/shared/:id/cmdb/:type/:name 0
 */
class SharedGroupCMDBSpecificItem extends CMDBResource
{
    use SharedGroupVerification;
    /**
     * @var CmdbItemModel
     */
    private $cmdbItemModel;
    private $sharedHostGroupsModel;

    public function __construct($parameters)
    {
        parent::__construct($parameters);
        $this->cmdbItemModel = new SharedGroupCmdbModel($this->username);
        $this->sharedHostGroupsModel = new SharedHostGroupsModel($this->username);

        if (!isActionAllowed($this->username, 'host-groups-shared.get')) {
            throw new AccessDenyException("Action is not allowed. Permission to view shared group is missing.");
        }
    }

    /**
     * @rbacName Get data
     * @rbacGroup Shared host group configuration management data
     * @rbacAlias shared-group-cmdb.get
     * @rbacAllowedByDefault
     */
    public function get($request, $groupId, $type, $name)
    {
        $response = new \Response($request);
        $response->code = \Response::OK;

        if (!$this->isSharedGroupExists($groupId)) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

        try {
            $data = $this->cmdbItemModel->getByName($groupId, $type, $name);
            $response->body = json_encode($data);
        } catch (\InvalidArgumentException $exception) {
            $response->body = $exception->getMessage();
            $response->code = \Response::BADREQUEST;
        }

        if ($data === null) {
            $response->body = "$type data with name $name is not found";
            $response->code = \Response::NOTFOUND;
        }

        return $response;
    }

    /**
     * @rbacName Create data
     * @rbacGroup Shared host group configuration management data
     * @rbacAlias shared-group-cmdb.create
     */
    public function post($request, $groupId, $type, $name)
    {
        $requestData = json_decode($request->data, $associative = true);
        CMDBSpecificItem::validateCMDBRequest($name, $requestData);
        $response = new \Response($request);
        $response->code = \Response::OK;

        if (!$this->isSharedGroupExists($groupId)) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

        try {
            $this->cmdbItemModel->insertOrUpdateByName($groupId, $type, $name, $requestData);
            $this->sharedHostGroupsModel->sendCmdbRefreshPsqlNotification();
        } catch (\InvalidArgumentException $exception) {
            $response->body = $exception->getMessage();
            $response->code = \Response::BADREQUEST;
        }

        return $response;
    }

    /**
     * @rbacName Update data
     * @rbacGroup Shared host group configuration management data
     * @rbacAlias shared-group-cmdb.update
     */
    public function patch($request, $groupId, $type, $name)
    {
        $requestData = json_decode($request->data, $associative = true);
        CMDBSpecificItem::validateCMDBRequest($name, $requestData);
        $response = new \Response($request);
        $response->code = \Response::OK;

        if (!$this->isSharedGroupExists($groupId)) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

        $existingConfig = $this->cmdbItemModel->getByName($groupId, $type, $name);

        if ($existingConfig === null) {
            $response->body = "$type data with name $name is not found";
            $response->code = \Response::NOTFOUND;
            return $response;
        }

        try {
            $this->cmdbItemModel->updateByName($groupId, $type, $name, $requestData, $existingConfig);
            $this->sharedHostGroupsModel->sendCmdbRefreshPsqlNotification();
        } catch (\InvalidArgumentException $exception) {
            $response->body = $exception->getMessage();
            $response->code = \Response::BADREQUEST;
        }

        return $response;
    }

    /**
     * @rbacName Delete data
     * @rbacGroup Shared host group configuration management data
     * @rbacAlias shared-group-cmdb.delete
     */
    public function delete($request, $groupId, $type, $name)
    {
        $response = new \Response($request);
        $response->code = \Response::NOCONTENT;

        if (!$this->isSharedGroupExists($groupId)) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

        try {
            $this->cmdbItemModel->deleteByName($groupId, $type, $name);
            $this->sharedHostGroupsModel->sendCmdbRefreshPsqlNotification();
        } catch (\InvalidArgumentException $exception) {
            $response->body = $exception->getMessage();
            $response->code = \Response::BADREQUEST;
        }

        return $response;
    }


}
