<?php


/**
 * @uri /host-groups/shared/ 0
 */
class SharedHostGroups extends CfProtectedResource
{
    private $sharedHostGroupsModel;

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

    /**
     * @rbacName Get shared host groups
     * @rbacGroup Shared Host Groups API
     * @rbacAlias host-groups-shared.get
     * @rbacAllowedByDefault
     */
    public function get($request)
    {
        $response = new Response($request);
        $response->code = Response::OK;
        $args = $_GET;
        if (isset($args['sortColumn']) && !in_array($args['sortColumn'], SharedHostGroupEntity::sortableColumns())) {
            throw new InvalidArgumentException("sortColumn `{$args['sortColumn']}` is not allowed.");
        }
        $args['username'] = $this->username;
        $response->body = json_encode($this->sharedHostGroupsModel->list($args, ['deletion_time IS NULL']));
        return $response;
    }

    /**
     * @rbacName Create shared host groups
     * @rbacGroup Shared Host Groups API
     * @rbacAlias host-groups-shared.post
     */
    public function post($request)
    {
        $response = new Response($request);
        $response->code = Response::CREATED;

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

        $requestData->creator = $this->username;
        $sharedGroup = new SharedHostGroupEntity(...(array)$requestData);

        if (!$this->sharedHostGroupsModel->isNameUnique($sharedGroup->getName())) {
            throw new InvalidArgumentException('Shared group with the same name already exists.');
        }

        if ($sharedGroup->validate()) {
            $id = $this->sharedHostGroupsModel->create($sharedGroup);
            $this->sharedHostGroupsModel->sendCmdbRefreshPsqlNotification();
            $response->body = json_encode(['id' => $id]);
            AuditLogService::register([
                AuditLogFields::ACTOR => $this->username,
                AuditLogFields::OBJECT_TYPE => AuditLogObjectTypes::GROUP,
                AuditLogFields::OBJECT_ID => $id,
                AuditLogFields::OBJECT_NAME => $sharedGroup->getName(),
                AuditLogFields::ACTION => AuditLogActions::CREATE,
                AuditLogFields::DETAILS => ["Created shared group `{$sharedGroup->getName()}`."]
            ]);
        }

        return $response;
    }

}

/**
 * @uri /host-groups/shared/:id 0
 */
class SharedHostGroup extends CfProtectedResource
{
    private $sharedHostGroupsModel;

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

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


    /**
     * @rbacName Get shared host groups
     * @rbacGroup Shared Host Groups API
     * @rbacAlias host-groups-shared.get
     * @rbacAllowedByDefault
     */
    public function get($request, $id)
    {
        $response = new Response($request);
        $response->code = Response::OK;
        if (!$group = $this->sharedHostGroupsModel->get(intval($id))) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

        $response->body = json_encode($group);
        return $response;
    }


    /**
     * @rbacName Update shared host groups
     * @rbacGroup Shared Host Groups API
     * @rbacAlias host-groups-shared.patch
     * @rbacDescription  Update filter, name and priority, excluding group data
     */
    public function patch($request, $id)
    {
        $id = intval($id);
        $response = new Response($request);
        $response->code = Response::OK;

        if (!($group = $this->sharedHostGroupsModel->get($id))) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

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

        // create group entity from the database output
        $groupEntity = new SharedHostGroupEntity();

        if (isset($requestData->name) && !empty($requestData->name)) {
            Validator::name($requestData->name);
            $groupEntity->setName($requestData->name);
        }

        if (isset($requestData->description) && !empty($requestData->description)) {
            $groupEntity->setDescription($requestData->description);
        }

        if (isset($requestData->filter) && !empty($requestData->filter)) {
            $groupEntity->setFilter($requestData->filter);
        }


        if (isset($requestData->priority) && !empty($requestData->priority)) {
            $groupEntity->setPriority((int)$requestData->priority);
        }

        if (!$this->sharedHostGroupsModel->isNameUnique($groupEntity->getName(), $id)) {
            throw new InvalidArgumentException('Shared group with the same name already exists.');
        }

        $this->sharedHostGroupsModel->update($id, $groupEntity);
        if (sizeof(array_intersect( // trigger cmdb config refresh if filter or priority were changed
            $groupEntity->getChangedItems(),
            [SharedHostGroupEntity::PRIORITY_COLUMN_NAME, SharedHostGroupEntity::FILTER_COLUMN_NAME]
        )) > 0) {
            $this->sharedHostGroupsModel->sendCmdbRefreshPsqlNotification();
        }

        AuditLogService::register([
            AuditLogFields::ACTOR => $this->username,
            AuditLogFields::OBJECT_TYPE => AuditLogObjectTypes::GROUP,
            AuditLogFields::OBJECT_ID => $id,
            AuditLogFields::OBJECT_NAME => $group['name'],
            AuditLogFields::ACTION => AuditLogActions::UPDATE,
            AuditLogFields::DETAILS => ["Updated shared group `{$group['name']}`.", ['changed properties' => $groupEntity->getChangedItems()]]
        ]);

        $response->body = json_encode($this->sharedHostGroupsModel->get($id));

        return $response;
    }

    /**
     * @rbacName Delete shared host groups
     * @rbacGroup Shared Host Groups API
     * @rbacAlias host-groups-shared.delete
     */
    public function delete($request, $id)
    {
        $response = new Response($request);
        $response->code = Response::NOCONTENT;
        $sharedGroup = $this->sharedHostGroupsModel->get(intval($id));
        if (!$sharedGroup) {
            $response->code = Response::NOTFOUND;
            return $response;
        }
        $this->sharedHostGroupsModel->delete(intval($id));
        $this->sharedHostGroupsModel->sendCmdbRefreshPsqlNotification();

        AuditLogService::register([
            AuditLogFields::ACTOR => $this->username,
            AuditLogFields::OBJECT_TYPE => AuditLogObjectTypes::GROUP,
            AuditLogFields::OBJECT_ID => $id,
            AuditLogFields::ACTION => AuditLogActions::DELETE,
            AuditLogFields::OBJECT_NAME => $sharedGroup['name'],
            AuditLogFields::DETAILS => ["Deleted shared group `{$sharedGroup['name']}`."]
        ]);
        return $response;
    }
}

/**
 * @uri /host-groups/shared/by-hostkey/:hostkey
 */
class SharedHostGroupsByHostkey extends CfProtectedResource
{
    private $sharedHostGroupsModel;

    public function __construct($parameters)
    {
        parent::__construct($parameters);
        $this->sharedHostGroupsModel = new SharedHostGroupsModel($this->username);
    }
    /**
     * @rbacName Get shared host groups by hostkey
     * @rbacGroup Shared Host Groups API
     * @rbacAlias host-groups-shared.get
     */
    public function get($request, $hostkey)
    {
        $response = new Response($request);
        $response->code = Response::OK;
        $groups = $this->sharedHostGroupsModel->getByHostkey($hostkey);
        $response->body = json_encode($groups);
        return $response;
    }
}

/**
 * @uri /host-groups/shared/:id/makePersonal
 */
class MakeSharedHostGroupPersonal extends CfProtectedResource
{
    /**
     * @rbacAlias host-groups-shared.delete
     */
    public function post($request, $id)
    {
        $id = intval($id);
        $response = new Response($request);
        $response->code = Response::OK;

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

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

        if (!($group = $sharedHostGroupsModel->get($id))) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

        $sharedGroupsEntity = new SharedHostGroupEntity(...$group);
        $personalGroupsEntity = new PersonalHostGroupEntity(...$sharedGroupsEntity->toArray());
        $personalGroupsEntity->setOwner($this->username);

        $newID = $sharedHostGroupsModel->makePersonal($id, $personalGroupsEntity, $personalHostGroupsModel);
        $response->body = json_encode(['id' => $newID]);

        AuditLogService::register([
            AuditLogFields::ACTOR => $this->username,
            AuditLogFields::OBJECT_TYPE => AuditLogObjectTypes::GROUP,
            AuditLogFields::OBJECT_ID => $id,
            AuditLogFields::ACTION => AuditLogActions::DELETE,
            AuditLogFields::OBJECT_NAME => $sharedGroupsEntity->getName(),
            AuditLogFields::DETAILS => ["Converted shared group `{$sharedGroupsEntity->getName()}` to a personal group."]
        ]);

        return $response;
    }
}

/**
 * @uri /host-groups/shared/:id/favorite
 */
class SharedHostGroupFavorite extends CfProtectedResource
{
    private $sharedHostGroupsModel;
    private $favoriteHostGroupsModel;

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

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


    /**
     * @rbacName Add group to favorite
     * @rbacGroup Shared Host Groups API
     * @rbacAlias host-groups-shared-favorite.post
     * @rbacAllowedByDefault
     */
    public function post($request, $id)
    {
        $id = intval($id);
        $response = new Response($request);
        $response->code = Response::OK;

        if (!$this->sharedHostGroupsModel->get($id)) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

        $this->favoriteHostGroupsModel->add($id, $this->username);
        return $response;
    }

    /**
     * @rbacName Remove group from favorite
     * @rbacGroup Shared Host Groups API
     * @rbacAlias host-groups-shared-favorite.delete
     * @rbacAllowedByDefault
     */
    public function delete($request, $id)
    {
        $response = new Response($request);
        $response->code = Response::NOCONTENT;

        if (!$this->sharedHostGroupsModel->get(intval($id))) {
            $response->code = Response::NOTFOUND;
            return $response;
        }

        $this->favoriteHostGroupsModel->remove($id, $this->username);
        return $response;
    }
}
