<?php 
class permission implements crudable {

	protected static array $fields=array(
			'projectid'=>validator::INTEGER,
			'usergroupid'=>validator::INTEGER,
			'type'=>validator::PERMISSIONTYPE
	);
	
	protected static array $helpTexts=array(
			'projectid'=>'The ID of the project',
			'usergroupid'=>'The ID of the usergroup',
			'type'=>'What permission is being granted - create, read, update or delete'
	);
	
	public static function getFieldValidations(): array {
		return self::$fields;
	}
	public static function getFieldHelpTexts(): array {
		return self::$helpTexts;
	}

	private static array $changePermissions=array('create','update','delete');

	/**
	 * @param int $id
	 * @return array
	 * @throws BadRequestException
	 * @throws ServerException
	 */
	public static function getById(int $id): array {
		$sqlStatement='SELECT * FROM permission WHERE id=:id';
		return database::queryGetOne($sqlStatement, array(':id'=>$id));
	}

	/**
	 * @param string $name
	 * @return array|null
	 * @throws ServerException
	 */
	public static function getByName(string $name): ?array {
		throw new ServerException('getByName not implemented on permission');
	}

	/**
	 * @param string $key
	 * @param string $value
	 * @param array $request
	 * @return array|null
	 * @throws ServerException
	 */
	public static function getByProperty(string $key, string $value, array $request=[]): ?array {
		throw new ServerException('getByProperty not implemented on permission');
	}

	/**
	 * @param array $keyValuePairs
	 * @param array $request
	 * @return array|null
	 * @throws ServerException
	 */
	public static function getByProperties(array $keyValuePairs, array $request=[]): ?array {
		throw new ServerException('getByProperties not implemented on permission');
	}

	/**
	 * @param array $request
	 * @throws ServerException
	 */
	public static function getAll(array $request=[]): array {
		throw new ServerException('getAll not implemented on permission');
	}

    /**
     * @param array $request
     * @return array
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
	public static function create(array $request=[]): array {
		$projectId=$request['projectid'];
		$usergroupId=$request['usergroupid'];
		$type=$request['type'];
		$project=project::getById($projectId);
		if(!$project){
			throw new NotFoundException('Project does not exist, or you do not have permission to see it');
		}
		usergroup::getbyid($usergroupId); //throws exception if the usergroup can't be read
		validator::validate($type, $request['type'], self::$fields['type']);
		if(!session::isAdmin() && session::getUserId()!=$project['owner']){
			throw new ForbiddenException('Only administrators and project owners can change groups\' project permissions');
		}
		$allPermissions=['read','create','update','delete'];
		if(!in_array($type, $allPermissions)){
		    throw new BadRequestException('Bad permission type ('.$type.') in permission::create');
        }
		//Delete all the old permissions for this project/group combination
		foreach($allPermissions as $oldPermission){
            $params=array(':projectid'=>$projectId, ':usergroupid'=>$usergroupId, ':type'=>$oldPermission);
            $sqlStatement='DELETE FROM permission WHERE projectid=:projectid AND usergroupid=:usergroupid AND type=:type';
            database::query($sqlStatement, $params);
        }
		//If read, create only read permission, else create read,create,update,delete permissions
		$created=[];
		if('read'==$type){
		    $newPermissions=['read'];
        } else {
		    $newPermissions=$allPermissions;
        }
		foreach ($newPermissions as $newPermission){
            $sqlStatement='INSERT INTO permission(projectid,usergroupid,type) VALUES(:projectid,:usergroupid,:type)';
            $params=array(':projectid'=>$projectId, ':usergroupid'=>$usergroupId, ':type'=>$newPermission);
            database::query($sqlStatement, $params);
            $lastId=database::getLastInsertId();
            $created[]=permission::getById($lastId);
        }
		return array('created'=>$created);
	}

	/**
	 * @param int $id
	 * @param array $request
	 * @return array
	 * @throws ServerException
	 */
	public static function update(int $id, array $request=[]): array {
		throw new ServerException('Update not implemented on permission');
	}

	/**
	 * Deletes the permission. If permission type is one of "create","update","delete",
	 * all create/update/delete permissions for this project and usergroup will be deleted.
	 * @param int $id
	 * @return array
	 * @throws BadRequestException
	 * @throws ForbiddenException
	 * @throws NotFoundException
	 * @throws ServerException
	 */
	public static function delete(int $id): array {
		$permission=self::getbyid($id);
		$project=project::getbyid($permission['projectid']);
		$usergroup=usergroup::getbyid($permission['usergroupid']);
		$type=$permission['type'];
		if(empty($permission) || empty($project) || empty($usergroup) ){ 
			throw new NotFoundException('Permission does not exist or you cannot read it'); 
		}
		if(!session::isAdmin() && session::getUserId()!=$project['owner']){
			throw new ForbiddenException('Only administrators and project owners can change groups\' project permissions');
		}

		$deletedPermissions=[];
		$permissionsToDelete=static::$changePermissions;
		if('read'==$type){
		    $permissionsToDelete[]='read';
        } else if(!in_array($type, static::$changePermissions)) {
            throw new ServerException('Bad permission type ('.$type.') in permission::delete');
        }
		foreach ($permissionsToDelete as $permissionToDelete) {
            $existing=database::queryGetOne('SELECT * FROM permission 
                WHERE projectid=:projectid AND usergroupid=:usergroupid AND type=:type',
                array(
                    ':projectid'=>$permission['projectid'],
                    ':usergroupid'=>$permission['usergroupid'],
                    ':type'=>$permissionToDelete
                )
            );
            if(!empty($existing)){
                $deletedPermissions[]=$existing;
                $sqlStatement='DELETE FROM permission WHERE id=:id';
                database::query($sqlStatement, array(':id'=>$existing['id']));
            }
        }
        return array('deleted'=>$deletedPermissions);
	}

	public static function canCreate(): bool {
		return true; // and let the actual create sort it out
	}

	/**
	 * @param int $id
	 * @return bool
	 */
	public static function canUpdate(int $id): bool {
		return true; // and let the actual update sort it out
	}

	/**
	 * Find the database ID of a permission, from its project ID, usergroup ID, and permission type (read, delete, etc.).
	 * @throws ServerException
	 * @throws BadRequestException
	 */
	public static function getPermissionId(int $projectId, int $usergroupId, string $permissionType): ?int {
		$permission=database::queryGetOne('SELECT id FROM permission WHERE projectid=:projectid 
                            AND usergroupid=:usergroupid AND type=:type',
			[':projectid'=>$projectId, ':usergroupid'=>$usergroupId, ':type'=>$permissionType]
		);
		if(empty($permission)){ return null; }
		return $permission['id'];
	}

}